--- title: Lido on Ethereum V2 upgrade template. Audit scope tags: scope, withdrawals, template, audits authors: Eugene Mamin, Artem Veremeenko --- ## Lido on Ethereum V2 upgrade template. Audit scope * Created: 2022-03-10 * Updated: 2023-04-12 --- ### Simple summary A single contract to be used for the Lido DAO Aragon vote that performs on-chain actions for the Lido V1→V2 upgrade on behalf of the Lido DAO. ### Context Lido V2 upgrade changes almost every previously deployed contract and adds new ones. From the prospects of the governance process, an on-chain vote for the upgrade should perform an atomic (all or nothing) transition. The upgrade template encompasses migrations, permissions granting procedures, and overall protocol integrity checks. The template contract will be used on the third step of the Lido protocol upgrade scheme: Step 1: Deploy new contracts and updated implementations from EOA. Step 2: Deploy a new template with the hardcoded addresses of the deployed artifacts. Step 3: Run an on-chain Aragon vote to execute the template using the entitled `Voting` contract For information: the vote structure is presented in the [`upgrade_shapella_1.py`](https://github.com/lidofinance/scripts/blob/shapella-upgrade/scripts/upgrade_shapella_1.py) and [`upgrade_shapella_2_revoke_roles.py`](https://github.com/lidofinance/scripts/blob/shapella-upgrade/scripts/upgrade_shapella_2_revoke_roles.py) upgrade scripts. ### Scope of the audit [`ShapellaUpgradeTemplate.sol`](https://github.com/lidofinance/scripts/blob/shapella-upgrade/contracts/shapella-upgrade/ShapellaUpgradeTemplate.sol) On-chain code size: **~650** nSLOC (using the [[1]](https://github.com/ConsenSys/solidity-metrics) method) The contract is written in Solidity 0.8.9. ### Additionally required services of the audit The `ShapellaUpgradeTemplate` contract will be changed one last time before the actual upgrade on mainnet to hardcode the deployed addresses of the verified `Lido V2` contracts. The service of deployment verification is vital for this audit that includes: - verification of the template contract on mainnet - verification of the hardcoded addresses inside the template against the `Lido V2` verified contracts addresses on mainnet - formal report chapter that both verifications are completed successfully ### Final commit to audit The final commit to audit is: [`8f9bfb2f0616fec031d382c4ec5e3455e7ebcd07`](https://github.com/lidofinance/scripts/blob/8f9bfb2f0616fec031d382c4ec5e3455e7ebcd07/contracts/shapella-upgrade/ShapellaUpgradeTemplate.sol) ## Edits log - 2022-04-12: Fixed commit id: [8f9bfb2f0616fec031d382c4ec5e3455e7ebcd07](https://github.com/lidofinance/scripts/blob/8f9bfb2f0616fec031d382c4ec5e3455e7ebcd07/contracts/shapella-upgrade/ShapellaUpgradeTemplate.sol), notes updated. ## External references - [Lido V2 on-chain code](https://github.com/lidofinance/lido-dao/releases/tag/v2.0.0-beta.2) - [Lido V2 audit scope](https://hackmd.io/aDD_xw_vQ_mUDei9ZokHZg?view) - [An example of the upgrade vote (the Merge case)](https://github.com/lidofinance/scripts/blob/master/archive/scripts/vote_2022_05_24.py#L108..L164) - [Lido V2 upgrade signal approval vote](https://snapshot.org/#/lido-snapshot.eth/proposal/0x629b547c688dea536a4a5c5b42274894ac068df0b0278d173b4d7a68c8c4281d) --- ### Appendixes #### Appendix 1. Rough actions plan ##### Step 1. EOA deployment In advance. Most of the admin roles stay on deployerEOA. Part are set to `Voting` at once. - deploy empty proxies for: - `WithdrawalQueue`, `ValidatorExitBusOracle`, `AccountingOracle`, `StakingRouter`, `LidoLocator` - deploy implementations for all of the empty proxies from step above - deploy non-upgradable contracts: - `DepositSecurityModule`, `OracleReportSanityChecker`, `OracleDaemonConfig`, `EIP712StETH`, `Burner`, `HashConsensus for AccountingOracle`, `HashConsensus for ValidatorsExitBusOracle` - update `LidoLocator` implementation with all the addresses known - deploy `GateSeal` contract ##### Step 2. UpgradeTemplate deployment - hardcode addresses and parameters in `UpgradeTemplate` contract - deploy `UpgradeTemplate` from `DeployerEOA` - verify configuration of the deployed `UpgradeTemplate` (on etherscan) - pass all admin roles from `deployerEOA` to `UpdateTemplate` ##### Step 3. Start Aragon voting - start Aragon voting 1: - upgrade `WithdrawalManagerStub` implementation to `WithdrawalVault` - call `UpgradeTemplate.startUpgrade()` - update implementations of `Lido`, `NodeOperatorsRegistry`, `LidoOracle` - grant `STAKING_ROUTER_ROLE` of `NodeOperatorsRegistry` to `StakingRouter` - call `UpgradeTemplate.finishUpgrade()` - start Aragon voting 2: - call `UpgradeTemplate.revertIfUpgradeNotFinished` - revoke aragon roles (list) - verify upgrade #### Appendix 2. Admin roles lifecycle - set to `Voting` at initial deployment - oracleDaemonConfig - oracleReportSanityChecker - set to `deployerEOA` at initial deployment. passed to `UpgradeTemplate` before start of Aragon voting - locator proxy owner - stakingRouter proxy owner - accountingOracle proxy owner - validatorsExitBusOracle proxy owner - withdrawalQueue proxy owner - hashConsensusForAccountingArgs admin - hashConsensusForExitBusArgs admin - burner admin - depositSecurityModule owner - set to `UpgradeTemplate` by `UpgradeTemplate` via `initialize()` calls. Passed to `Voting` during `UpgradeTemplate.finishUpgrade()` - stakingRouter - accountingOracle - validatorsExitBusOracle - withdrawalQueue