Try   HackMD

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 and upgrade_shapella_2_revoke_roles.py upgrade scripts.

Scope of the audit

ShapellaUpgradeTemplate.sol

On-chain code size:
~650 nSLOC (using the [1] 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

Edits log

External references


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