Skip to content

Commit

Permalink
Merge branch 'repovation' into feat/restore-deployed-files
Browse files Browse the repository at this point in the history
  • Loading branch information
tamtamchik committed Sep 6, 2024
2 parents c4f4593 + 7febc70 commit 315e7ef
Show file tree
Hide file tree
Showing 58 changed files with 2,231 additions and 1,080 deletions.
9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,12 @@ MAINNET_STAKING_ROUTER_ADDRESS=
MAINNET_VALIDATORS_EXIT_BUS_ORACLE_ADDRESS=
MAINNET_WITHDRAWAL_QUEUE_ADDRESS=
MAINNET_WITHDRAWAL_VAULT_ADDRESS=

; Forking URL for mainnet hardhat fork
HARDHAT_FORKING_URL=

; Scratch deployment via hardhat variables
DEPLOYER=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
GENESIS_TIME=1639659600
GAS_PRIORITY_FEE=1
GAS_MAX_FEE=100
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on: [push]

jobs:
test_hardhat_integration_fork:
name: Hardhat / Mainnet Fork
name: Hardhat / Mainnet
runs-on: ubuntu-latest
timeout-minutes: 120

Expand All @@ -26,6 +26,6 @@ jobs:
run: cp .env.example .env

- name: Run integration tests
run: yarn test:integration:fork
run: yarn test:integration:fork:mainnet
env:
LOG_LEVEL: debug
6 changes: 3 additions & 3 deletions .github/workflows/tests-integration-scratch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on: [push]

jobs:
test_hardhat_integration_scratch:
name: Hardhat / Scratch deployment
name: Hardhat / Scratch
runs-on: ubuntu-latest
timeout-minutes: 120

Expand All @@ -24,9 +24,9 @@ jobs:
run: cp .env.example .env

- name: Run scratch deployment
run: ./scripts/scratch/dao-local-deploy.sh || exit 0
run: ./scripts/dao-ci-deploy.sh

- name: Run integration tests
run: yarn test:integration:local
run: yarn test:integration:fork:scratch
env:
LOG_LEVEL: debug
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ foundry/out/
.env
accounts.json
deployed-local.json
deployed-hardhat.json

# MacOS
.DS_Store
27 changes: 19 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,24 +203,35 @@ yarn test:integration:trace # Run all integration tests with trace logging
yarn test:integration:fulltrace # Run all integration tests with full trace logging (calls and storage ops)
```
###### Local setup
###### Hardhat Scratch Deploy Fork
This method is used to run integration tests against a local scratch deployment (
see [scratch-deploy.md](./docs/scratch-deploy.md)).
Requires a local deployment to be running on port `8555` and `deployed-local.json` with the deployed addresses
(automatically generated during the scratch deployment).
This method is used to run integration tests against a Hardhat local scratch deployment instead of the mainnet fork.
Requires `DEPLOYER`, `GENESIS_TIME`, `GAS_PRIORITY_FEE` and `GAS_MAX_FEE` to be set in the `.env` file.
```bash
yarn test:integration:local
yarn test:integration:scratch # Run all integration tests
yarn test:integration:scratch:trace # Run all integration tests with trace logging (calls only)
yarn test:integration:scratch:fulltrace # Run all integration tests with full trace logging (calls and storage ops)
```
###### Any fork setup
###### Any Mainnet Fork
This method is used to run integration tests against any fork. Requires `MAINNET_*` env variables to be set in the
`.env` file and a fork to be running on port `8545`.
```bash
yarn test:integration:fork
yarn test:integration:fork:mainnet
```
###### Any Scratch Deploy Fork
This method is used to run integration tests against a local scratch deployment
(see [scratch-deploy.md](./docs/scratch-deploy.md)).
Requires a local deployment to be running on port `8555` and `deployed-local.json` with the deployed addresses
(automatically generated during the scratch deployment).
```bash
yarn test:integration:fork:scratch
```
#### Foundry tests
Expand Down
83 changes: 57 additions & 26 deletions docs/scratch-deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ This scratch deployment manual is partially outdated and is a subject of further
Do

```shell
anvil -p 8555
anvil -p 8555 --base-fee 0 --gas-price 0
```

and

```shell
bash scripts/scratch/dao-local-deploy.sh
bash scripts/dao-local-deploy.sh
```

## Requirements
Expand All @@ -26,11 +26,17 @@ bash scripts/scratch/dao-local-deploy.sh

The repo contains bash scripts for deployment of the DAO under multiple environments:

- local node (ganache, anvil, hardhat network) `scripts/scratch/dao-local-deploy.sh`
- holesky testnet - `scripts/scratch/dao-holesky-deploy.sh`
- local node (ganache, anvil, hardhat network) `scripts/dao-local-deploy.sh`
- holesky testnet - `scripts/dao-holesky-deploy.sh`

The protocol has a bunch of parameters to configure for the scratch deployment. The default configuration is stored in files `deployed-<deploy env>-defaults.json`, where `<deploy env>` is the target environment. Currently, there is a single default configuration, `deployed-testnet-defaults.json`, suitable for testnet deployments. Compared to the mainnet configuration, it has lower vote durations, more frequent oracle report cycles, etc. Part of the parameters require further specification -- they are marked with `null` values.
During the deployment, the "default" configuration is copied to `deployed-<network name>.json`, where `<network name>` is the name of a network configuration defined in `hardhat.config.js`. The file `deployed-<network name>.json` gets populated with the contract addresses and transaction hashes during the deployment process.
The protocol has a bunch of parameters to configure for the scratch deployment. The default configuration is stored in
files `deployed-<deploy env>-defaults.json`, where `<deploy env>` is the target environment. Currently, there is a
single default configuration, `deployed-testnet-defaults.json`, suitable for testnet deployments. Compared to the
mainnet configuration, it has lower vote durations, more frequent oracle report cycles, etc. Part of the parameters
require further specification -- they are marked with `null` values.
During the deployment, the "default" configuration is copied to `deployed-<network name>.json`, where `<network name>`
is the name of a network configuration defined in `hardhat.config.js`. The file `deployed-<network name>.json` gets
populated with the contract addresses and transaction hashes during the deployment process.

These are the deployment setups, supported currently:

Expand All @@ -39,7 +45,8 @@ These are the deployment setups, supported currently:

Each is described in the details in the sections below.

> NB: Aragon UI for Lido DAO is to be deprecated and replaced by a custom solution, thus not included in the deployment script.
> NB: Aragon UI for Lido DAO is to be deprecated and replaced by a custom solution, thus not included in the deployment
> script.
### Deploy steps

Expand All @@ -63,26 +70,34 @@ A brief description of what's going on under the hood in the deploy script.
- Deploy Lido custom Aragon apps repo contracts (via `LidoTemplate`)
- Deploy Lido DAO (via `LidoTemplate`)
- Issue DAO tokens (via `LidoTemplate`)
- Deploy non-Aragon Lido contracts: `OracleDaemonConfig`, `LidoLocator`, `OracleReportSanityChecker`, `EIP712StETH`, `WstETH`, `WithdrawalQueueERC721`, `WithdrawalVault`, `LidoExecutionLayerRewardsVault`, `StakingRouter`, `DepositSecurityModule`, `AccountingOracle`, `HashConsensus` for AccountingOracle, `ValidatorsExitBusOracle`, `HashConsensus` for ValidatorsExitBusOracle, `Burner`.
- Finalize Lido DAO deployment: issue unvested LDO tokens, set Aragon permissions, register Lido DAO name in Aragon ID (via `LidoTemplate`)
- Deploy non-Aragon Lido contracts: `OracleDaemonConfig`, `LidoLocator`, `OracleReportSanityChecker`, `EIP712StETH`,
`WstETH`, `WithdrawalQueueERC721`, `WithdrawalVault`, `LidoExecutionLayerRewardsVault`, `StakingRouter`,
`DepositSecurityModule`, `AccountingOracle`, `HashConsensus` for AccountingOracle, `ValidatorsExitBusOracle`,
`HashConsensus` for ValidatorsExitBusOracle, `Burner`.
- Finalize Lido DAO deployment: issue unvested LDO tokens, set Aragon permissions, register Lido DAO name in Aragon ID (
via `LidoTemplate`)
- Initialize non-Aragon Lido contracts
- Set parameters of `OracleDaemonConfig`
- Setup non-Aragon permissions
- Plug NodeOperatorsRegistry as Curated staking module
- Transfer all admin roles from deployer to `Agent`
- OZ admin roles: `Burner`, `HashConsensus` for `AccountingOracle`, `HashConsensus` for `ValidatorsExitBusOracle`, `StakingRouter`, `AccountingOracle`, `ValidatorsExitBusOracle`, `WithdrawalQueueERC721`, `OracleDaemonConfig`
- OssifiableProxy admins: : `LidoLocator`, `StakingRouter`, `AccountingOracle`, `ValidatorsExitBusOracle`, `WithdrawalQueueERC721`
- OZ admin roles: `Burner`, `HashConsensus` for `AccountingOracle`, `HashConsensus` for `ValidatorsExitBusOracle`,
`StakingRouter`, `AccountingOracle`, `ValidatorsExitBusOracle`, `WithdrawalQueueERC721`, `OracleDaemonConfig`
- OssifiableProxy admins: : `LidoLocator`, `StakingRouter`, `AccountingOracle`, `ValidatorsExitBusOracle`,
`WithdrawalQueueERC721`
- `DepositSecurityModule` owner

## Local deployment

Deploys the DAO to local (http://127.0.0.1:8555) dev node (anvil, hardhat, ganache).
The deployment is done from the default test account `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266` derived from the default mnemonic.
Thus the node must be configured with the default test accounts derived from the mnemonic `test test test test test test test test test test test junk`.
The deployment is done from the default test account `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266` derived from the
default mnemonic.
Thus the node must be configured with the default test accounts derived from the mnemonic
`test test test test test test test test test test test junk`.

1. Run `yarn install` (get sure repo dependencies are installed)
2. Run the node on port 8555 (for the commands, see subsections below)
3. Run the deploy script `bash scripts/scratch/dao-local-deploy.sh` from root repo directory
3. Run the deploy script `bash scripts/dao-local-deploy.sh` from root repo directory
4. Check out the deploy artifacts in `deployed-local.json`

### Anvil
Expand All @@ -107,15 +122,21 @@ yarn hardhat node

To do Holešky deployment, the following parameters must be set up via env variables:

- `DEPLOYER`. The deployer address. The deployer must own its private key. To ensure proper operation, it should have an adequate amount of ether. The total deployment gas cost is approximately 120,000,000 gas, and this cost can vary based on whether specific components of the environment, such as the DepositContract, are deployed or not.
- `RPC_URL`. Address of of the Ethereum RPC node to use. E.g. for Infura it is `https://holesky.infura.io/v3/<yourProjectId>`
- `DEPLOYER`. The deployer address. The deployer must own its private key. To ensure proper operation, it should have an
adequate amount of ether. The total deployment gas cost is approximately 120,000,000 gas, and this cost can vary based
on whether specific components of the environment, such as the DepositContract, are deployed or not.
- `RPC_URL`. Address of of the Ethereum RPC node to use. E.g. for Infura it is
`https://holesky.infura.io/v3/<yourProjectId>`
- `GAS_PRIORITY_FEE`. Gas priority fee. By default set to `2`
- `GAS_MAX_FEE`. Gas max fee. By default set to `100`
- `GATE_SEAL_FACTORY`. Address of the [GateSeal Factory](https://github.com/lidofinance/gate-seals) contract. Must be deployed in advance. Can be set to any `0x0000000000000000000000000000000000000000` to debug deployment
- `GATE_SEAL_FACTORY`. Address of the [GateSeal Factory](https://github.com/lidofinance/gate-seals) contract. Must be
deployed in advance. Can be set to any `0x0000000000000000000000000000000000000000` to debug deployment
- `WITHDRAWAL_QUEUE_BASE_URI`. BaseURI for WithdrawalQueueERC712. By default not set (left an empty string)
- `DSM_PREDEFINED_ADDRESS`. Address to use instead of deploying `DepositSecurityModule` or `null` otherwise. If used, the deposits can be made by calling `Lido.deposit` from the address.
- `DSM_PREDEFINED_ADDRESS`. Address to use instead of deploying `DepositSecurityModule` or `null` otherwise. If used,
the deposits can be made by calling `Lido.deposit` from the address.

Also you need to specify `DEPLOYER` private key in `accounts.json` under `/eth/holesky` like `"holesky": ["<key>"]`. See `accounts.sample.json` for an example.
Also you need to specify `DEPLOYER` private key in `accounts.json` under `/eth/holesky` like `"holesky": ["<key>"]`. See
`accounts.sample.json` for an example.

To start the deployment, run (the env variables must already defined) from the root repo directory:

Expand All @@ -137,33 +158,42 @@ NETWORK=<PUT-YOUR-VALUE> RPC_URL=<PUT-YOUR-VALUE> bash ./scripts/scratch/verify-

There are some contracts deployed from other contracts for which automatic hardhat etherscan verification fails:

- `AppProxyUpgradeable` of multiple contracts (`app:lido`, `app:node-operators-registry`, `app:oracle`, `app:voting`, ...)
- `AppProxyUpgradeable` of multiple contracts (`app:lido`, `app:node-operators-registry`, `app:oracle`,
`app:voting`, ...)
- `KernelProxy` -- proxy for `Kernel`
- `AppProxyPinned` -- proxy for `EVMScriptRegistry`
- `MiniMeToken` -- LDO token
- `CallsScript` -- Aragon internal contract
- `EVMScriptRegistry` -- Aragon internal contract

The workaround used during Holešky deployment is to deploy auxiliary instances of these contracts standalone and verify them via hardhat Etherscan plugin. After this Etherscan will mark the target contracts as verified by "Similar Match Source Code".
The workaround used during Holešky deployment is to deploy auxiliary instances of these contracts standalone and verify
them via hardhat Etherscan plugin. After this Etherscan will mark the target contracts as verified by "Similar Match
Source Code".

NB, that some contracts require additional auxiliary contract to be deployed. Namely, the constructor of `AppProxyPinned` depends on proxy implementation ("base" in Aragon terms) contract with `initialize()` function and `Kernel` contract, which must return the implementation by call `kernel().getApp(KERNEL_APP_BASES_NAMESPACE, _appId)`. See `@aragon/os/contracts/apps/AppProxyBase.sol` for the details.
NB, that some contracts require additional auxiliary contract to be deployed. Namely, the constructor of
`AppProxyPinned` depends on proxy implementation ("base" in Aragon terms) contract with `initialize()` function and
`Kernel` contract, which must return the implementation by call `kernel().getApp(KERNEL_APP_BASES_NAMESPACE, _appId)`.
See `@aragon/os/contracts/apps/AppProxyBase.sol` for the details.

## Post deploy initialization

### Initialization up to the fully operational state

In order to make the protocol fully operational, the additional steps are required:

- add oracle committee members to `HashConsensus` contracts for `AccountingOracle` and `ValidatorsExitBusOracle`: `HashConsensus.addMember`;
- initialize initial epoch for `HashConsensus` contracts for `AccountingOracle` and `ValidatorsExitBusOracle`: `HashConsensus.updateInitialEpoch`;
- add oracle committee members to `HashConsensus` contracts for `AccountingOracle` and `ValidatorsExitBusOracle`:
`HashConsensus.addMember`;
- initialize initial epoch for `HashConsensus` contracts for `AccountingOracle` and `ValidatorsExitBusOracle`:
`HashConsensus.updateInitialEpoch`;
- add guardians to `DepositSecurityModule`: `DepositSecurityModule.addGuardians`;
- resume protocol: `Lido.resume`;
- resume WithdrawalQueue: `WithdrawalQueueERC721.resume`;
- add at least one Node Operator: `NodeOperatorsRegistry.addNodeOperator`;
- add validator keys to the Node Operators: `NodeOperatorsRegistry.addSigningKeys`;
- set staking limits for the Node Operators: `NodeOperatorsRegistry.setNodeOperatorStakingLimit`.

NB, that part of the actions require prior granting of the required roles, e.g. `STAKING_MODULE_MANAGE_ROLE` for `StakingRouter.addStakingModule`:
NB, that part of the actions require prior granting of the required roles, e.g. `STAKING_MODULE_MANAGE_ROLE` for
`StakingRouter.addStakingModule`:

```js
await stakingRouter.grantRole(STAKING_MODULE_MANAGE_ROLE, agent.address, { from: agent.address });
Expand All @@ -180,7 +210,8 @@ await stakingRouter.renounceRole(STAKING_MODULE_MANAGE_ROLE, agent.address, { fr

## Protocol parameters

This section describes part of the parameters and their values used at the deployment. The values are specified in `deployed-testnet-defaults.json`.
This section describes part of the parameters and their values used at the deployment. The values are specified in
`deployed-testnet-defaults.json`.

### OracleDaemonConfig

Expand Down
6 changes: 4 additions & 2 deletions docs/upgrade-deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ postTokenRebaseReceiver=<PUT-YOU-VALUE> \
GAS_MAX_FEE=100 GAS_PRIORITY_FEE=2 \
DEPLOYER=<PUT-YOU-VALUE> \
RPC_URL=<PUT-YOU-VALUE> \
yarn hardhat --network sepolia run --no-compile scripts/upgrade/deploy-locator.ts
STEPS_FILE=scripts/upgrade/steps.json \
yarn hardhat --network sepolia run --no-compile scripts/utils/migrate.ts
```

specifying require values under `<PUT-YOU-VALUE>`.

Names of env variables specifying new addresses (e.g. `postTokenRebaseReceiver`) correspond to immutables names of `LidoLocator` contract.
Names of env variables specifying new addresses (e.g. `postTokenRebaseReceiver`) correspond to immutables names of
`LidoLocator` contract.
3 changes: 2 additions & 1 deletion globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ declare namespace NodeJS {
LOG_LEVEL?: "all" | "debug" | "info" | "warn" | "error" | "none";

/* flags for changing the behavior of the integration tests */
INTEGRATION_SIMPLE_DVT_MODULE?: "on" | "off";
INTEGRATION_SCRATCH_DEPLOY?: "on" | "off"; // if "on" test will use scratch deploy instead of forking
INTEGRATION_SIMPLE_DVT_MODULE?: "on" | "off"; // if "on" test will use simple DVT module instead of linking NOR

/**
* Network configuration for the protocol discovery.
Expand Down
11 changes: 10 additions & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,17 @@ import { mochaRootHooks } from "test/hooks";

const RPC_URL: string = process.env.RPC_URL || "";
const HARDHAT_FORKING_URL = process.env.HARDHAT_FORKING_URL || "";
const INTEGRATION_SCRATCH_DEPLOY = process.env.INTEGRATION_SCRATCH_DEPLOY || "off";
const ACCOUNTS_PATH = "./accounts.json";

/**
* Determines the forking configuration for Hardhat.
* @returns The forking configuration object or undefined.
*/
function getHardhatForkingConfig() {
return INTEGRATION_SCRATCH_DEPLOY === "on" || !HARDHAT_FORKING_URL ? undefined : { url: HARDHAT_FORKING_URL };
}

function loadAccounts(networkName: string) {
// TODO: this plaintext accounts.json private keys management is a subject
// of rework to a solution with the keys stored encrypted
Expand Down Expand Up @@ -58,7 +67,7 @@ const config: HardhatUserConfig = {
count: 30,
accountsBalance: "100000000000000000000000",
},
forking: HARDHAT_FORKING_URL ? { url: HARDHAT_FORKING_URL } : undefined,
forking: getHardhatForkingConfig(),
},
"sepolia": {
url: RPC_URL,
Expand Down
8 changes: 3 additions & 5 deletions lib/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,15 @@ export async function addContractHelperFields(contract: BaseContract, name: stri
}

export async function loadContract<ContractType extends BaseContract>(
factory: ContractFactoryHelper<ContractType>,
name: string,
address: string,
signer?: HardhatEthersSigner,
) {
if (!signer) {
signer = await ethers.provider.getSigner();
}
const result = factory.connect(address, signer as ContractRunner);
const factoryName = factory.name;
const contractName = factoryName.slice(0, factoryName.indexOf("__"));
return (await addContractHelperFields(result, contractName)) as unknown as LoadedContract<ContractType>;
const result = await ethers.getContractAt(name, address, signer);
return (await addContractHelperFields(result, name)) as unknown as LoadedContract<ContractType>;
}

export async function getContractAt(name: string, address: string): Promise<LoadedContract> {
Expand Down
Loading

0 comments on commit 315e7ef

Please sign in to comment.