TL;DR
This post outlines the deployment plan for a fix addressing the Dual Governance weakness reported through Immunefi. The fix involves redeploying certain Dual Governance contracts, configuring them, and linking the existing EmergencyProtectedTimelock
and Admin Executor
contracts to a newly deployed DualGovernance
instance.
The fix was audited by Certora and is currently being reviewed by Statemind, which will also verify the deployment and review the tooling contracts used during the voting phase. A special Immunefi contest was conducted on the fixed version of the contracts, with no vulnerabilities identified during the process.
Upgrade Components
Due to the immutable structure of the Dual Governance contracts, the fix requires disconnecting the EmergencyProtectedTimelock
from the current DualGovernance
instance and connecting it to a newly deployed version with the fix applied.
The TiebreakerCoreCommittee
, along with its subcommittees, will also be updated, as it includes immutable reference to the DualGovernance
contract. The composition of the committee and its subcommittees will remain unchanged, as stated in the original post.
The old DualGovernance
instance will be reconfigured with a new ImmutableDualGovernanceConfigProvider
to prevent entry into a vulnerable state and allow users to freely withdraw funds from the old Escrow
.
After the upgrade, the final Dual Governance setup will look as shown below:
The full list of upgraded contracts is:
-
Contracts to disconnect:
- Dual Governance - 0xcdF49b058D606AD34c5789FD8c3BF8B3E54bA2db
- Veto Signaling Escrow - 0xA8F14D033f377779274Ae016584a05bF14Dccaf8 (proxy)
- Escrow - 0xb84317C0E142D8911A0d69Dc32c48d87753B8d1C (impl)
- Tiebreaker Core Committee - 0x175742c3DDD88B0192df3EcF98f180A79cb259D0
- Tiebreaker Sub Committees:
- Builders Sub Committee - 0x74836470337Ba5d2a92fe16E44AD862E28fcf9B3
- Node Operators Sub Committee - 0xb9d82E1A49f6a66E8a07260BA05Cf9Ac8a938B1C
- Ethereum Ecosystem Sub Committee - 0x7dAdae4e1a0DB43F6bcfA75295666fc044605679
-
Newly deployed contracts:
- Dual Governance - 0xC1db28B3301331277e307FDCfF8DE28242A4486E
- Veto Signaling Escrow - 0x165813A31446a98c84E20Dda8C101BB3C8228e1c (proxy)
- Escrow - 0xd6A67636c05BeB5B4a5c90D408b03A63c4e39426 (impl)
- Tiebreaker Core Committee - 0xf65614d73952Be91ce0aE7Dd9cFf25Ba15bEE2f5
- Tiebreaker Sub Committees:
- Builders Sub Committee - 0x3D3ba54D54bbFF40F2Dfa2A8e27bD4dE3dab2951
- Node Operators Sub Committee - 0xDBfa0B8A15a503f25224fcA5F84a3853230A715C
- Ethereum Ecosystem Sub Committee - 0xBF048f2111497B6Df5E062811f5fC422804D4baE
- Dual Governance Config Provider for disconnected DualGovernance contract - 0xc934E90E76449F09f2369BB85DCEa056567A327a
During the upgrade the following tooling contracts will be used:
DGUpgradeOmnibusMainnet
0x67988077f29FbA661911d9567E05cc52C51ca1B0 - contains the list of the vote items required to apply the Dual Governance fix.DGUpgradeStateVerifierMainnet
0x487b764a2085ffd595D9141BAec0A766B7904786 - called as the final step of the vote to confirm that the contracts have been configured correctly.
The full list of contracts is also available in the documentation.
Vote Structure
To apply the fix, the DGUpgradeOmnibusMainnet
contract contains a single Aragon vote item that submits a Dual Governance proposal with the following actions:
- Finalize the configuration of the new
DualGovernance
instance — which can only be performed by the AdminExecutor
— to match the current mainnet setup:- Set the tiebreaker activation timeout to 31536000 seconds (1 year).
- Set the tiebreaker committee address to the newly deployed Tiebreaker Core Committee.
- Add
WithdrawalQueue
andValidatorExitBusOracle
as sealable withdrawal blockers. - Register Aragon
Voting
as Proposer, assigning it to the current AdminExecutor
. - Set Aragon
Voting
as Proposals Canceller. - Set the Reseal Committee address to
0xFFe21561251c49AdccFad065C94Fb4931dF49081
(Reseal Committee, used in the current setup).
- Set the
Governance
address in theEmergencyProtectedTimelock
to the newly deployedDualGovernance
instance. - Replace the config provider in the old
DualGovernance
with the newImmutableDualGovernanceConfigProvider
, effectively “bricking” the old instance and ensuring it cannot enter a vulnerable state, even unintentionally. - Verify the resulting state of the new
DualGovernance
onchain using theDGUpgradeStateVerifierMainnet
contract to ensure all steps were executed correctly.
Notes
The current DualGovernance
and Escrow
contract instances will be detached from the EmergencyProtectedTimelock
, making user interaction with them highly unlikely, though not entirely impossible. To ensure the old Escrow
cannot enter a vulnerable state, the outdated DualGovernance
instance will be updated to use a new configuration provider contract. This configuration sets:
- RageQuit support thresholds to their maximum values - 100% for the second seal and 99.(9)₁₆% for the first seal - making it virtually impossible for the old
DualGovernance
to enter the RageQuit state. - All other parameters are set to minimal values, allowing users to unlock their funds without a timelock if they were mistakenly locked in the old
Escrow
instance.
Verification
The contract fix has been audited by Certora and is currently under review by Statemind. Statemind will also perform deployment verification and review the vote-related DGUpgradeOmnibusMainnet
and DGUpgradeStateVerifierMainnet
contracts.
All reports will be published before the vote goes onchain.
The upgrade was successfully completed and tested on the Hoodi testnet, with contract bytecode identical to that deployed on mainnet.
Thanks
Lido Contributors are thankful to the whitehat reporter and security partners — Immunefi, Certora, and Statemind.
Note to tokenholders: please stay tuned for the upgrade vote in the upcoming voting slot.
Context links
Security disclosure post
New contract addresses
Certora Audit report