From e645f1fa322ccb9fc2e14821642013cfe13a0a3d Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Fri, 14 Jul 2023 18:07:56 +0300 Subject: [PATCH] doc: start protocol levers refresh --- docs/guides/protocol-levers.md | 126 +++++++++++------- docs/security/roles-roster.md | 5 + .../token-guides/steth-superuser-functions.md | 53 -------- sidebars.js | 6 +- 4 files changed, 88 insertions(+), 102 deletions(-) create mode 100644 docs/security/roles-roster.md delete mode 100644 docs/token-guides/steth-superuser-functions.md diff --git a/docs/guides/protocol-levers.md b/docs/guides/protocol-levers.md index 4d1259f2b..9f2befe93 100644 --- a/docs/guides/protocol-levers.md +++ b/docs/guides/protocol-levers.md @@ -7,7 +7,7 @@ the DAO voting, and other entities can be allowed to do the same only as a resul All existing levers are listed below, grouped by the contract. -### A note on upgradeability +## A note on upgradeability The following contracts are upgradeable by the DAO voting: @@ -22,9 +22,10 @@ The following contracts are upgradeable by the DAO voting: - [`LegacyOracle`](/contracts/legacy-oracle) Upgradeability is implemented either by the Aragon kernel and base contracts OR by the [OssifiableProxy](/contracts/ossifiable-proxy) instances. -To upgrade an Aragon app, one needs the `dao.APP_MANAGER_ROLE` permission provided by Aragon. -To upgrade an `OssifiableProxy` implementation, one needs to be an owner of the proxy. -As it was said previously, both belong either to the DAO `Voting` or `Agent` apps. + +- To upgrade an Aragon app, one needs the `dao.APP_MANAGER_ROLE` permission provided by Aragon. +- To upgrade an `OssifiableProxy` implementation, one needs to be an owner of the proxy. +- As it was said previously, both belong either to the DAO [`Voting`](https://etherscan.io/address/0x2e59A20f205bB85a89C53f1936454680651E618e) or [`Agent`](https://etherscan.io/address/0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c) apps. All upgradeable contracts use the [Unstructured Storage pattern] in order to provide stable storage structure across upgrades. @@ -32,39 +33,42 @@ All upgradeable contracts use the [Unstructured Storage pattern] in order to pro Some of the contracts still contain structured storage data, hence the order of inheritance always matters. ::: -[unstructured storage pattern]: https://blog.openzeppelin.com/upgradeability-using-unstructured-storage +[Unstructured Storage pattern]: https://blog.openzeppelin.com/upgradeability-using-unstructured-storage ## [Lido](/contracts/lido) ### Burning stETH tokens -There is a dedicated contract responsible for `stETH` tokens burning. -The burning itself is a part of the core protocol procedures: +The `stETH` token burning itself is a part of the core protocol regular procedures: - deduct underlying finalized withdrawal request `stETH`, see [`Lido.handleOracleReport`](/contracts/lido#handleOracleReport) - penalize delinquent node operators by halving their rewards, see [`NodeOperatorsRegistry._distributeRewards](/contracts/node-operators-registry#_distributeRewards) -These responsibilities are controlled by the `REQUEST_BURN_SHARES_ROLE` role which is assigned to both +These responsibilities are controlled by the [`REQUEST_BURN_SHARES_ROLE`](https://etherscan.io/address/0xD15a672319Cf0352560eE76d9e89eAB0889046D3#readContract#F3) role which is assigned to both [`Lido`](/contracts/lido) and [`NodeOperatorsRegistry`](/contracts/node-operators-registry) contracts. -This role should not be ever permanently assigned to another entities. -Apart from this, `stETH` token burning can be applied to compensate for penalties/slashing losses by the DAO decision. -It's possible via more restrictive role `REQUEST_BURN_MY_STETH_ROLE` which is currently unassigned. +:::note +The `REQUEST_BURN_SHARES_ROLE` role should not be ever permanently assigned to another entities. +::: + +Apart from this, the `stETH` token burning can be applied to compensate for penalties/slashing losses by the DAO decision. +It's possible via the more restrictive role [`REQUEST_BURN_MY_STETH_ROLE`](https://etherscan.io/address/0xD15a672319Cf0352560eE76d9e89eAB0889046D3#readContract#F2) which is currently unassigned. The key difference that despite of both roles rely on the `stETH` allowance provided to the `Burner` contract, -the latter allows token burning only from the request originator balance. +the latter allows token burning only from the request originator balance not relying on general allowance. ### Pausing - Mutator: `stop()` - - Permission required: `PAUSE_ROLE` + - Permission required: [`PAUSE_ROLE`](https://etherscan.io/address/0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84#readProxyContract#F13) - Mutator: `resume()` - - Permission required: `RESUME_ROLE` + - Permission required: [`RESUME_ROLE`](https://etherscan.io/address/0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84#readProxyContract#F8) - Accessor: `isStopped() returns (bool)` When paused, `Lido` doesn't accept user submissions, doesn't allow user withdrawals and oracle -report submissions. No token actions (burning, transferring, approving transfers and changing -allowances) are allowed. The following transactions revert: +report submissions. No token ownership-changing actions (burning, transferring) are allowed. + +The following transactions revert if Lido is paused: - plain Ether transfers to `Lido`; - calls to `submit(address)`; @@ -73,10 +77,7 @@ allowances) are allowed. The following transactions revert: - calls to `transfer(address, uint256)`; - calls to `transferFrom(address, address, uint256)`; - calls to `transferShares(address, uint256)`; -- calls to `transferSharesFrom(address, uint256)`; -- calls to `approve(address, uint256)`; -- calls to `increaseAllowance(address, uint256)`; -- calls to `decreaseAllowance(address, uint256)`. +- calls to `transferSharesFrom(address, uint256)`. As a consequence of the list above: @@ -96,18 +97,70 @@ External stETH/wstETH DeFi integrations are directly affected as well. The method unsafely changes deposited validator counter. Can be required when onboarding external validators to Lido (i.e., had deposited before and rotated their type-0x00 withdrawal credentials to Lido). +:::note The incorrect values might disrupt protocol operation. +::: ### Oracle report -TODO: oracle reports are committee-driven +StETH is a rebasable token. + +It receives reports from the `AccoutingOracle` contract (via the `Lido.handleOracleReport` method) with the state of the protocol's Consensus Layer validators balances, and updates all the balances of stETH holders distributing the protocol's total staking rewards and penalties. This result in a change of the balances of all `stETH` holders. + +The protocol employs distributed Oracle reporting: there are **nine** Oracle daemons running by the Lido Node operators, and the Oracle smart contract formats beacon report on the consensus of **five** of **nine** daemon reports. On top of the consensus mechanics, there are sanity checks for reports with sudden drops in total Consensus Layer balance or rewards with higher-than-possible APY and other security measurements. + +The oracle committee is responsible for delivering two types of reports: + +- Protocol's accounting data to [`AccountingOracle`](/contracts/accounting-oracle): Consensus Layer validators state, +balances of the execution layer and withdrawal vaults, `stETH` amount already requested to burn, and withdrawal request ranges to be finalized. +- Validator exits requests to [`ValidatorsExitBus`](/contracts/validators-exit-bus-oracle): validator indexes to request a voluntary exit propagation from the side of a node operator + +Note that: + +- The Lido DAO can set another addresses for the oracle contracts (it was case with the Lido V2 upgrade) +- The implementation of the contract can be changed as well + +#### Oracle committee members + +The following addresses form the Lido oracle members set and only they are allowed to push the new oracle data. + +| Name | Mainnet address | Görli address | +| ------------------- | -------------------------------------------- | ---------------------------------------------- | +| Chorus One | [`0x140bd8fbdc884f48da7cb1c09be8a2fadfea776e`] | [`0xA8aF49FB44AAA8EECa9Ae918bb7c05e2E71c9DE9`] | +| Jumpcrypto | [`0x1d0813bf088be3047d827d98524fbf779bc25f00`] | [`0x1a13648EE85386cC101d2D7762e2848372068Bc3`] | +| Staking Facilities | [`0x404335bce530400a5814375e7ec1fb55faff3ea2`] | [`0xb29dD2f6672C0DFF2d2f173087739A42877A5172`] | +| P2P | [`0x007de4a5f7bc37e2f26c0cb2e8a95006ee9b89b5`] | [`0xfdA7E01B2718C511bF016030010572e833C7aE6A`] | +| Stakefish | [`0x946d3b081ed19173dc83cd974fc69e1e760b7d78`] | [`0xD3b1e36A372Ca250eefF61f90E833Ca070559970`] | +| Rated | [`0xec4bfbaf681eb505b94e4a7849877dc6c600ca3a`] | [`0x3799bDA7B884D33F79CEC926af21160dc47fbe05`] | +| bloXroute | [`0x61c91ECd902EB56e314bB2D5c5C07785444Ea1c8`] | [`0x4c75FA734a39f3a21C57e583c1c29942F021C6B7`] | +| Instadapp | [`0x1ca0fec59b86f549e1f1184d97cb47794c8af58d`] | [`0x81E411f1BFDa43493D7994F82fb61A415F6b8Fd4`] | +| Kyber Network | [`0xA7410857ABbf75043d61ea54e07D57A6EB6EF186`] | [`0x3fF28f2EDE8358E288798afC23Ee299a503aD5C9`] | + +[`0x140bd8fbdc884f48da7cb1c09be8a2fadfea776e`]: https://etherscan.io/address/0x140bd8fbdc884f48da7cb1c09be8a2fadfea776e +[`0x1d0813bf088be3047d827d98524fbf779bc25f00`]: https://etherscan.io/address/0x1d0813bf088be3047d827d98524fbf779bc25f00 +[`0x404335bce530400a5814375e7ec1fb55faff3ea2`]: https://etherscan.io/address/0x404335bce530400a5814375e7ec1fb55faff3ea2 +[`0x007de4a5f7bc37e2f26c0cb2e8a95006ee9b89b5`]: https://etherscan.io/address/0x007de4a5f7bc37e2f26c0cb2e8a95006ee9b89b5 +[`0x946d3b081ed19173dc83cd974fc69e1e760b7d78`]: https://etherscan.io/address/0x946d3b081ed19173dc83cd974fc69e1e760b7d78 +[`0xec4bfbaf681eb505b94e4a7849877dc6c600ca3a`]: https://etherscan.io/address/0xec4bfbaf681eb505b94e4a7849877dc6c600ca3a +[`0x61c91ECd902EB56e314bB2D5c5C07785444Ea1c8`]: https://etherscan.io/address/0x61c91ECd902EB56e314bB2D5c5C07785444Ea1c8 +[`0x1ca0fec59b86f549e1f1184d97cb47794c8af58d`]: https://etherscan.io/address/0x1ca0fec59b86f549e1f1184d97cb47794c8af58d +[`0xA7410857ABbf75043d61ea54e07D57A6EB6EF186`]: https://etherscan.io/address/0xA7410857ABbf75043d61ea54e07D57A6EB6EF186 +[`0xA8aF49FB44AAA8EECa9Ae918bb7c05e2E71c9DE9`]: https://goerli.etherscan.io/address/0xA8aF49FB44AAA8EECa9Ae918bb7c05e2E71c9DE9 +[`0x1a13648EE85386cC101d2D7762e2848372068Bc3`]: https://goerli.etherscan.io/address/0x1a13648EE85386cC101d2D7762e2848372068Bc3 +[`0xb29dD2f6672C0DFF2d2f173087739A42877A5172`]: https://goerli.etherscan.io/address/0xb29dD2f6672C0DFF2d2f173087739A42877A5172 +[`0xfdA7E01B2718C511bF016030010572e833C7aE6A`]: https://goerli.etherscan.io/address/0xfdA7E01B2718C511bF016030010572e833C7aE6A +[`0xD3b1e36A372Ca250eefF61f90E833Ca070559970`]: https://goerli.etherscan.io/address/0xD3b1e36A372Ca250eefF61f90E833Ca070559970 +[`0x3799bDA7B884D33F79CEC926af21160dc47fbe05`]: https://goerli.etherscan.io/address/0x3799bDA7B884D33F79CEC926af21160dc47fbe05 +[`0x4c75FA734a39f3a21C57e583c1c29942F021C6B7`]: https://goerli.etherscan.io/address/0x4c75FA734a39f3a21C57e583c1c29942F021C6B7 +[`0x81E411f1BFDa43493D7994F82fb61A415F6b8Fd4`]: https://goerli.etherscan.io/address/0x81E411f1BFDa43493D7994F82fb61A415F6b8Fd4 +[`0x3fF28f2EDE8358E288798afC23Ee299a503aD5C9`]: https://goerli.etherscan.io/address/0x3fF28f2EDE8358E288798afC23Ee299a503aD5C9 ### Deposit access control The `Lido.deposit` method performs an actual deposit (stake) of buffered ether to Consensus Layer -undergoing through `StakingRouter`, its selected module, and the official Ethereum deposit contract in the end. +undergoing through `StakingRouter`, its selected module, and the official [Ethereum deposit contract](https://ethereum.org/en/staking/deposit-contract/) in the end. -The method can be called only by `DepositSecurityModule` since access control is a part of the deposits frontrunning vulnerability mitigation. +The method can be called only by [`DepositSecurityModule`](/contracts/deposit-security-module) since access control is a part of the deposits frontrunning vulnerability mitigation. Please see [LIP-5](https://github.com/lidofinance/lido-improvement-proposals/blob/develop/LIPS/lip-5.md) for more details. @@ -128,22 +181,7 @@ if the amount of the buffered Ether becomes sufficiently large. ### Execution layer rewards -Lido implements an architecture design which was proposed in the Lido Improvement Proposal [#12](https://github.com/lidofinance/lido-improvement-proposals/blob/develop/LIPS/lip-12.md) to collect the execution level rewards (starting from the Merge hardfork) and distribute them as part of the Lido Oracle report. - -These execution layer rewards are initially accumulated on the dedicated [`LidoExecutionLayerRewardsVault`](/contracts/lido-execution-layer-rewards-vault) contract and consists of priority fees and MEV. - -There is an additional limit to prevent drastical token rebase events. -See the following issue: [`#405`](https://github.com/lidofinance/lido-dao/issues/405) - -- Mutator: `setELRewardsVault()` - - Permission required: `SET_EL_REWARDS_VAULT_ROLE` - -- Mutator: `setELRewardsWithdrawalLimit()` - - Permission required: `SET_EL_REWARDS_WITHDRAWAL_LIMIT_ROLE` - -- Accessors: - - `getELRewardsVault()`; - - `getELRewardsWithdrawalLimit()`. +TODO ### Staking rate limiting @@ -152,6 +190,7 @@ Lido features a safeguard mechanism to prevent huge APR losses facing the [post- New staking requests could be rate-limited with a soft moving cap for the stake amount per desired period. Limit explanation scheme: + ``` * ▲ Stake limit * │..... ..... ........ ... .... ... Stake limit = max @@ -212,7 +251,6 @@ Credentials to withdraw ETH on the Execution Layer side The protocol uses these credentials to register new Ethereum validators. - ## [NodeOperatorsRegistry](/contracts/node-operators-registry) ### Node Operators list @@ -260,13 +298,7 @@ Allow to manage signing keys for the given node operator. Allows to report that `_stoppedIncrement` more validators of a node operator have become stopped. -## [LegacyOracle](/contracts/legacy-oracle) - -### Lido - -Address of the Lido contract. - -- Accessor: `getLido() returns (address)` +## [AccountingOracle](/contracts/accounting-oracle) and [ValidatorsExitBusOracle](/contracts/validators-exit-bus-oracle) ### Members list diff --git a/docs/security/roles-roster.md b/docs/security/roles-roster.md new file mode 100644 index 000000000..d56ad86fb --- /dev/null +++ b/docs/security/roles-roster.md @@ -0,0 +1,5 @@ +# Roles roster and holders + +## Core protocol + +## L2 bridges diff --git a/docs/token-guides/steth-superuser-functions.md b/docs/token-guides/steth-superuser-functions.md deleted file mode 100644 index fa95bb030..000000000 --- a/docs/token-guides/steth-superuser-functions.md +++ /dev/null @@ -1,53 +0,0 @@ -# StETH superuser functions - - - -## Superuser privileges and accounts - -StETH token is the upgradable contract behind `AppProxyUpgradeable` proxy at [https://etherscan.io/address/0xae7ab96520de3a18e5e111b5eaab095312d7fe84](https://etherscan.io/address/0xae7ab96520de3a18e5e111b5eaab095312d7fe84). Lido DAO can change the implementation with the successful DAO vote. - -StETH can be stopped by the DAO vote. No operations changing stETH balances can be performed on the stopped contract: - -1. `transfer` call reverts; -2. No mints or burns can be performed. Note that StETH contract can mint stETH only in two cases: user deposits (tokens are minted to the depositor's address) or fee distribution (where tokens are minted in accordance to fee calculations to the addresses set in the contract — namely the DAO treasury, the insurance fund and the Node Operator's reward addresses); -3. Users can't submit their ETH to the Lido; -4. Oracle can't push updates on the Consensus Layer staking state; -5. No ETH buffered in Lido can be sent to the Ethereum deposit contract; -6. Staking withdrawals can't be performed. - -## Superuser roles - -TODO: Outdated `BURN_ROLE` - -StETH contract specifies PAUSE_ROLE (address can pause the protocol) and BURN_ROLE (address can burn stETH tokens): - -* The `PAUSE_ROLE` assigned only to the DAO Voting contract [https://etherscan.io/address/0x2e59a20f205bb85a89c53f1936454680651e618e](https://etherscan.io/address/0x2e59a20f205bb85a89c53f1936454680651e618e) -* The `BURN_ROLE` assigned to the [`Burner`](/contracts/burner) contract with additional ACL parameters effectively allowing to burn stETH tokens only from the contract own balance. Tokens could be requested to burn only by direct request from the DAO Voting. - -Note that there are other roles for DAO management, but they don't affect the token actions. These roles are MANAGE_FEE (set staking fee amount), MANAGE_WITHDRAWAL_KEY (set withdrawal credentials of the protocol), MANAGE_PROTOCOL_CONTRACTS_ROLE (set oracle contract address, set DAO treasury address to send fee to, set DAO insurance address to send fee to). The roles and addresses can be checked in the Aragon UI [https://mainnet.lido.fi/#/lido-dao/permissions/app/0xae7ab96520de3a18e5e111b5eaab095312d7fe84](https://mainnet.lido.fi/#/lido-dao/permissions/app/0xae7ab96520de3a18e5e111b5eaab095312d7fe84) - -## Oracle rebasing reports - -StETH is a rebasable token. It receives reports from the Oracle contract (`handleOracleReport` method) with the state of the protocol's Consensus Layer validators balances, and updates all the balances of stETH holders distributing the protocol's total staking rewards and penalties. The protocol employs distributed Oracle reporting: there are five Oracle daemons running by the Lido Node operators, and the Oracle smart contract formats beacon report on the consensus of three of five daemon reports. On top of the consensus mechanics, there are sanity checks for reports with sudden drops in total Consensus Layer balance or rewards with higher-than-possible APY. Current Oracle contract is [https://etherscan.io/address/0x442af784A788A5bd6F42A01Ebe9F287a871243fb](https://etherscan.io/address/0x442af784A788A5bd6F42A01Ebe9F287a871243fb). Note that: 1) DAO can set another address for the Oracle contact via vote; 2) Oracle implementation can change via vote. - -## Superuser privileges decentralization - -The superuser privileges are managed by the Lido DAO's governance system. To enact any change the DAO has to have a successful vote. - -Oracles are: 1) limited in impact 2) distributed - there are five of them, all top-tier professional node operators. - -## Superuser actions thresholds - -The "superuser actions" with the StETH token are performed via DAO votes. The votes are managed by the Aragon voting. Voting power is proportional to the addresses' LDO token balance ([https://etherscan.io/token/0x5a98fcbea516cf06857215779fd812ca3bef1b32](https://etherscan.io/token/0x5a98fcbea516cf06857215779fd812ca3bef1b32)). For the voting to pass successfully, it should: 1) get at least 5% of the total LDOs to be cast "for" the vote; 2) get at least 50% of votes cast "for" the vote. The voting duration is 72 hours. - -There are five Oracle daemons running by the Lido Node operators, with 3 of 5 needed to agree on the data they provide. On top of the consensus mechanics, there are sanity checks for reports with sudden drops in total Consensus Layer balance or rewards with higher-than-possible APY. - -## Superuser keys management - -Token management roles belong to smart contracts, and any changes in roles must pass through the successful DAO vote. - -Oracle operators are: Stakefish, Certus One, Chorus One, Staking Facilities, P2P Validator. - -## Superuser keys generation procedure - -There was no special keygen ceremony, as the permissions are managed by smart contracts. The votes can be cast by the EOAs and smart contracts with the voting power proportional to the addresses' LDO balance. diff --git a/sidebars.js b/sidebars.js index 2139a398d..d4e5c6eb6 100644 --- a/sidebars.js +++ b/sidebars.js @@ -71,7 +71,6 @@ module.exports = { type: 'category', label: 'Token guides', items: [ - 'token-guides/steth-superuser-functions', 'token-guides/steth-on-aave-caveats', ], }, @@ -105,7 +104,10 @@ module.exports = { { type: 'category', label: 'Security', - items: ['security/bugbounty'], + items: [ + 'security/bugbounty', + 'security/roles-roster' + ], }, { type: 'category',