Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: accounting oracle integration tests on scratch deploy #199

Merged
merged 29 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b976533
chore: update scratch deploy libs
tamtamchik Aug 28, 2024
ddc1ccd
chore: add migrator
tamtamchik Aug 28, 2024
293b8c1
chore: update deployment steps
tamtamchik Aug 28, 2024
06d9853
fix: fix scratch deploy command
tamtamchik Aug 28, 2024
a00002c
chore: update ci scratch deploy script
tamtamchik Aug 28, 2024
b820ee5
fix: fix scratch deploy env
tamtamchik Aug 28, 2024
bd8c029
chore: restore scratch acceptance test file
tamtamchik Aug 28, 2024
5b1efb7
chore: remove factories
tamtamchik Aug 28, 2024
0e411d3
fix: typings
tamtamchik Aug 28, 2024
3d54394
chore: working local integration tests with scratch deploy and tracing
tamtamchik Aug 29, 2024
1a938f1
chore: update commands and docs
tamtamchik Aug 29, 2024
3f676ca
chore: review updates
tamtamchik Aug 30, 2024
0de12c0
Merge branch 'feat/integration-deployment' into feat/accounting-scratch
tamtamchik Aug 30, 2024
9a2f46c
fix: docs
tamtamchik Aug 30, 2024
02d9e83
Merge branch 'feat/integration-deployment' into feat/accounting-scratch
tamtamchik Aug 30, 2024
6dabfa3
chore: update migrator logic
tamtamchik Sep 2, 2024
becbce7
chore: unify migration config
tamtamchik Sep 2, 2024
eb91362
Merge branch 'master' into feat/integration-deployment
tamtamchik Sep 2, 2024
a093e76
Merge branch 'repovation' into feat/integration-deployment
tamtamchik Sep 3, 2024
ad59107
Merge branch 'feat/oracle-integration' into feat/accounting-scratch
tamtamchik Sep 3, 2024
0d8c410
Merge branch 'feat/integration-deployment' into feat/accounting-scratch
tamtamchik Sep 3, 2024
925d4fd
fix: cache deployment steps on multiple tests
tamtamchik Sep 3, 2024
af4643b
Merge branch 'feat/integration-deployment' into feat/accounting-scratch
tamtamchik Sep 3, 2024
81b018f
chore: some tooling upgrades
tamtamchik Sep 4, 2024
06f8c55
chore: improve resolution
tamtamchik Sep 4, 2024
f751ee9
chore: 9 of 10 accounting tests stabilized
tamtamchik Sep 4, 2024
1c6d9e0
chore: accounting should work
tamtamchik Sep 4, 2024
fa677e0
Merge branch 'repovation' into feat/accounting-scratch
tamtamchik Sep 5, 2024
788bbce
Merge branch 'feat/oracle-integration' into feat/accounting-scratch
tamtamchik Sep 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading