owned this note
                
                
                     
                     owned this note
                
                
                     
                    
                
                
                     
                    
                
                
                     
                    
                        
                            
                            Published
                        
                        
                            
                                
                                Linked with GitHub
                            
                            
                                
                                
                            
                        
                     
                
            
            
                
                    
                    
                
                
                    
                
                
                
                    
                        
                    
                    
                    
                
                
                
                    
                
            
            
         
        
        # 📝 Curated Module v2. Spec
:::warning
**This document is WIP.** Statements or schemes are not final and can not be referred to anywhere.
:::

Curated Module v2 (CM v2) is a new chapter for the Lido protocol. Based on the solid codebase of CSM, it features new concepts like support for 0x02 validators, integration features, and many more. A robust bonding mechanism allows CM v2 to streamline Node Operator management, reduce operational complexity, and increase protocol security. 
> Terms validator, key, validator key, and deposit data meanings are the same within the document
- [Project repo](https://github.com/lidofinance/community-staking-module)
- Written in [Solidity 0.8.24](https://github.com/ethereum/solidity/tree/v0.8.24)
- Developed in [Foundry](https://github.com/foundry-rs/foundry)
## General Architecture

The scheme above depicts CM v2's smart contracts architecture and changes made compared to CSM v2.
### Contracts
#### `CuratedModule.sol`
*CMv2 on the scheme* 
:::info
Changed in CM v2
:::
`CuratedModule.sol` is a core module contract conforming to the `IStakingModule` interface. The contract inherits from the original `CSModule.sol` to allow for the extended functionality while maintaining consistency with the original CSM. It stores information about Node Operators and deposit data (DD). This contract is responsible for all interactions with the `StakingRouter`, namely, the DD management and some of the Node Operator's parameters. Node Operators manage their validator keys and other parameters they can modify through this contract.
**Changes in CM v2:**
- The withdrawal reporting method is updated to support 0x02 WC type.
- The management system for the NodeOperators address is changed to allow DAO to set both `rewardAddress` and `managerAddress`.
- Exit penalties account for the validator withdrawal balance before application to support 0x02 WC type.
- Withdrawals of the slashed validators and slashing penalties are reported via ET.
#### `Accounting.sol`
*Accounting in the scheme* 
:::info
Changed in CM v2
:::
`Accounting.sol` is a supplementary contract responsible for the management of bond, rewards, and penalties. It stores bond tokens as `stETH` shares, provides information about the bond required, and provides interfaces for the penalties. Node Operators claim rewards and top-up bonds using this contract.
**Changes in CM v2:**
- `targetLimit` is now set to 0 if the penalty amount exceeds the bond available to effectively deactivate a Node Operator.
- `FeeSplits` functionality added.
- Infinite bond lock record is created in case of an insufficient bond to cover poenalties.
#### `Verifier.sol`
*Verifier on the scheme*
:::info
Changed in CM v2
:::
`Verifier.sol` is a utility contract responsible for validating the CL data proofs using EIP-4788. It accepts proof of the validator withdrawals and reports these facts to the `CuratedModule.sol` if the proof is valid.
**Changes in CM v2:**
- A special method is added to account for validator consolidations.
#### `FeeDistributor.sol`
*FeeDistributor on the scheme*
`FeeDistributor.sol` is a supplementary contract that stores non-claimed and non-distributed Node Operator rewards on its balance. This contract stores the latest root of a rewards distribution Merkle tree. It accepts calls from `Accounting.sol` with reward claim requests and stores data about already claimed rewards by the Node Operator. It receives non-distributed rewards from the `CuratedModule.sol` each time the `StakingRouter` mints the new portion of the module's rewards. This contract transfers excess rewards allocated by `StakingRouter` due to the variable Node Operator reward share back to the Lido treasury.
#### `FeeOracle.sol`
*FeeOracle on the scheme*
`FeeOracle.sol` is a utility contract responsible for the execution of the CSM Oracle report once the consensus is reached in the `HashConsensus.sol` contract, namely, transforming non-distributed rewards to non-claimed rewards stored on the `FeeDistributor.sol` and reporting the latest root of rewards distribution Merkle tree to the `FeeDistributor.sol`. Alongside rewards distribution, a contract manages strike data delivery to the `Strikes.sol`. A contract is inherited from the [`BaseOracle.sol`](https://github.com/lidofinance/core/blob/master/contracts/0.8.9/oracle/BaseOracle.sol) from Lido on Ethereum (LoE) core.
#### `HashConsensus.sol`
*HashConsensus on the scheme*
`HashConsensus.sol` is a utility contract responsible for reaching a consensus between CSM Oracle members. Uses the standard code of the [`HashConsensus`](https://github.com/lidofinance/core/blob/master/contracts/0.8.9/oracle/HashConsensus.sol) contract from Lido on Ethereum (LoE) core.
#### `ParametersRegistry.sol`
*ParametersRegistry on the scheme*
:::info
Changed in CM v2
:::
`ParametersRegistry.sol` is a utility contract that stores Node-Operator-type-related parameters fetched by the other smart contracts related to CSM. A contract requires a mandatory default value for all parameters to ensure consistency. The custom value is returned if it is set for a particular parameter. Otherwise, the default value is returned.
**Changes in CM v2:**
- Custom role for non-critical parameters management added.
#### `Strikes.sol`
*StrikesRegistry on the scheme*
`Strikes.sol` is a utility contract that stores information about strikes assigned to the CSM validators by CSM Performance Oracle. It has a permissionless method to prove that a particular validator should be ejected because the number of strikes is above the threshold for this validator. It calls `Ejector.sol` to perform a strikes threshold check and eject the validator.
#### `CuratedGate.sol`
*CuratedGates on the scheme*
:::info
New in CM v2
:::
`CuratedGate.sol` is a supplementary contract that enables Node Operator creation for the vetted addresses, which serves as an entry point to `CuratedModule.sol`. Alongside Node Operator creation, a contract can assign a custom Node Operator type (bondCurveId) in `Accounting.sol`. Deployed using `CuratedGateFactory.sol` to allow the addition of the new instances later without additional code security audits. The list of curated participants is individually upgradable for each instance of the `CuratedGate.sol`.
#### `CSEjector.sol`
*Ejector on the scheme*
`Ejector.sol` is a supplementary contract responsible for interactions with EIP-7002-powered Lido Withdrawal credentials via `VEB`. Node Operators can voluntarily eject their validators. `Strikes.sol` uses `Ejector.sol` to trigger exits for validators that have surpassed the strike threshold.
#### `ExitPenalties.sol`
*ExitPenalties on the scheme*
`ExitPenalties.sol` is a supplementary contract responsible for processing and storing information about exit-related penalties, namely:
- Delayed exit penalty.
- Bad performance ejection penalty.
- TE fee paid in case of a forced and involuntary exit.
#### `OperatorsData.sol`
*OperatorsData on the scheme*
:::info
New in CM v2
:::
`OperatorsData.sol` is a supplementary contract that stores Node Operator names and descriptions. Both Node Operators and the CM v2 Committee multisig can edit the values.
#### `EasyTrack`
`EasyTrack` is a utility contract responsible for applying the reported EL stealing penalties. A part of the common [`EasyTrack`](https://github.com/lidofinance/easy-track) setup within Lido on Ethereum (LoE).
#### `GateSeal`
`GateSeal` is a utility contract responsible for the one-time pause of the `CuratedModule.sol`, `Accounting.sol`, `FeeOracle.sol`, `CuratedGate.sol`, `Ejector.sol`, and `Verifier.sol` contracts to prevent possible module exploitation through zero-day vulnerabilities. Uses the [standard code](https://github.com/lidofinance/gate-seals) of the `GateSeal` contract from Lido on Ethereum (LoE).
The list of sealable contracts:
- `CuratedModule.sol`
- `Accounting.sol`
- `FeeOracle.sol`
- `Verifier.sol`
- `CuratedGate.sol` (multiple instances)
- `Ejector.sol`
### Off-chain tools
#### `CSM/CM Bot`
:::info
Changed in CM v2
:::
`CSM/CM Bot` is a daemon application responsible for monitoring and reporting the withdrawal events associated with the CSM and CM validators. Also responsible for validator ejection invocation due to strikes.
**Changes in CM v2:**
- The bot now also serves CM v2.
#### `EL stealing detector`
`EL stealing detector` is a daemon application or EOA or Committee Multisig responsible for detecting and reporting the EL stealing facts by the CSM validators. Assigned to CM v2 Committee Multisig and assumed to be re-assigned to the automated bot at the acceptable level of MEV monitoring software maturity to avoid false-positive activations.
#### `CM Oracle`
`CM Oracle` (also known as CM Performance Oracle) is a module in the common Lido on Ethereum (LoE) Oracle set. It is operated by the existing Oracles set alongside [Accounting Oracle](https://docs.lido.fi/contracts/accounting-oracle), [Validator Exit Bus Oracle](https://docs.lido.fi/contracts/validators-exit-bus-oracle), and CSM Performance Oracle. It is responsible for calculating the CM v2 Node Operators' reward distribution and strike assignment based on their performance on the CL.
## Main flows
### Create Node Operator
:::info
Changed in CM v2
- Node Operator creation is now done via `CuratedGates`.
:::

Node Operator creation uses `CuratedGate.sol` instances attached to `CuratedModule.sol` via `CREATE_NODE_OPERATOR_ROLE`. Unlike CSM, CM v2 assumes that the creation of the Node Operator is done without deposit data upload. Deposit data can be uploaded later using the flow below. 
Different instances of `CuratedGate.sol` represent different Node Operator types. Node Operators can either join Curated Module v2 or upgrade their Node Operator type using the `CuratedGate.sol` instance, where their address is added to the participants list. Once used, the address can not be used again.
### Upload deposit data

Node Operators can upload deposit data after creation. Before the upload, the amount of bond needed should be fetched from the `Accounting.sol`. Depending on the selected token, this amount should be:
- Attached as a payment to the transaction (ETH).
- Approved to be transferred by `Accounting.sol` (stETH, wstETH).
- Included in permit data approving transfers by `Accounting.sol` (stETH, wstETH).
### Delete deposit data

If deposit data has not been deposited yet, the Node Operator can request its deletion from `CuratedModule.sol`. `CuratedModule.sol` validates that deposit data has not yet been deposited. If deletion is possible and `keyRemovalCharge` is set for the Node Operator type, `Accounting.sol` confiscates the `keyRemovalCharge` from the Node Operator's bond.
:::info
`keyRemovalCharge` is expected to be 0 in CM v2.
:::
### Top-up bond without deposit data upload

CM v2 Node Operators can top up the bond balance at any time to have an excess bond in advance or compensate for the penalties. Top-up is done via `Accounting.sol`. Once funds are transferred to `Accounting.sol`, `CuratedModule.sol` is informed about the bond amount change, and corresponding changes in the depositable keys are performed regarding the Node Operator to account for the change in the bond balance.
### Stake allocation (deposit order)
:::info
Changed in CM v2
- FIFO queues replaced with the [MinFirstAllocation](https://docs.lido.fi/contracts/staking-router#allocation-algorithm) strategy extended with custom weights.
:::
CM v2 relies on the [MinFirstAllocation](https://docs.lido.fi/contracts/staking-router#allocation-algorithm) strategy, similar to the one used in StakingRouter and CM v1, to determine the order in which the keys should be provided for the deposits. The main change in the strategy is that custom weights are configurable per Node Operator type.
#### Basic flow

Once uploaded, deposit data becomes available for allocation. To allocate stake to the CM v2 Node Operators, `StakingRouter` calls the `obtainDepositData(depositsCount)` method to get the next `depositsCount` depositable keys determined by the MinFirstAllocation strategy.
#### Invalid keys

CM v2 utilizes the optimistic vetting approach. Any validator key uploaded to CM v2 is considered valid unless the opposite is reported. [DSM](https://docs.lido.fi/contracts/deposit-security-module) is responsible for detecting and reporting invalid keys through `StakingRouter`. If invalid keys are detected, a call to `decreaseOperatorVettedKeys` is expected from `StakingRouter` to `CuratedModule.sol`. As a result, the `VettedKeys` pointer will be decreased, and any new uploaded keys will not be vetted until Node Operators remove at least one key. Upon removal, the `VettedKeys` will be restored to `TotalKeys`. If the invalid keys are still present, the process will be repeated.
### Rewards distribution

`StakingRouter` mint rewards for CSM Node Operators on each report of the [`AccountingOracle`](https://docs.lido.fi/contracts/accounting-oracle). `CuratedModule.sol` transfers minted rewards to the `FeeDistributor.sol`. Once the report slot is reached for the following CM v2 Oracle report, the rewards distribution tree is calculated by each Oracle member. After reaching the quorum, a new Merkle tree root is submitted to the `FeeDistributor.sol`, the corresponding portion of the rewards is transferred from the non-distributed to the non-claimed state, and excess rewards transferred by `StakingRouter` due to variable Node Operator reward share are returned to the Lido treasury.
### Rewards claim
:::info
Changed in CM v2
- Optional built-in fee split added.
:::

Total rewards for the CM v2 Node Operators are comprised of bond rewards and staking fees. To claim the total rewards, the Node Operator needs to bring proof of the latest `cumulativeFeeShares` in the rewards tree. With that proof `Accounting.sol` pulls the Node Operator's portion of the staking fees from the `FeeDistributor.sol` and combines it with the Node Operator's bond. After that, all bond funds exceeding the bond required for the currently active keys are available for claim.
When staking fees are pulled from the `FeeDistributor.sol`, `Accounting.sol` fetches information about `FeeSplits` set for the given Node Operator and transfers corresponding fee shares to the `FeeSplitRecipients`. This allows for a seamless integration with the infrastructure providers like Obol and SVV, which charge a certain percentage of the staking rewards as a provider fee. Since there might be several `FeeSplitRecipients` (up to 5), this feature can also be used for the opt-in donations to the Protocol Guild or other public good funding services.
A special `pullFeeRewards` method allows the Node Operator to transfer staking rewards to the bond without transferring them to the reward address.
If there are no new rewards to pull from the `FeeDistributor.sol` Node Operator can still claim excess bond using the same flow.
:::info
The abbility to set a custom address for `claimRewardsXXX` methods is added to streamline reward claims management from the Node Operator side.
:::
### General penalty with confirmation
:::info
Changed in CM v2
- The EL rewards stealing penalty mechanism is extended to a general penalty.
- If the penalty is not compensated, CM v2 will set the `targetLimit` for the Node Operator to `0`, effectively phasing out the Node Operator.
:::

If the Node Operator violates CM v2 participation rules that are enforced off-chain (ex. violates the [Lido on Ethereum Block Proposer Rewards Policy](https://snapshot.box/#/s:lido-snapshot.eth/proposal/0x7ac2431dc0eddcad4a02ba220a19f451ab6b064a0eaef961ed386dc573722a7f)), this fact and the corresponding penalty amount are reported to the `CuratedModule.sol` by the off-chain actor. The reported amount of the bond funds (reported penalty + fixed fee) is locked by the `Accounting.sol`. Node Operator can compensate for the penalty and the fixed fee voluntarily. If the Node Operator does not compensate for the penalty, `EasyTrack` will be started to confirm the penalty application. Once enacted, a penalty is applied (locked funds are burned), and the `targetLimit` is set to `0` for the Node Operator, effectively phasing them out.
### Validator ejection due to strikes

If the validator has reached the strikes threshold (`actual strikes >= threshold`) `CSM/CM Bot` will initiate validator ejection using a permissionless method. `Strikes.sol` validates the proof and makes a call to `Ejector.sol` if the number of strikes >= threshold. `Ejector.sol` notify `TWG` about the required validator ejection. Corresponding penalties are recorded in `ExitPenalties.sol`.
:::info
It is planned not to use this functionality in CM v2
:::
### Voluntary validator ejection

If Node Operators want to use EIP-7002 to exit their validators, they can do so via a dedicated method in the `Ejector.sol` contract. In this case, `Ejector.sol` will notify `TWG` about the required validator ejection.
### Withdrawal reporting
:::info
Changed in CM v2
- The stuck penalty and bad performance penalty amounts are modified relative to the actual withdrawal balance to account for the non-full `0x02` validators.
- Two separate flows are introduced for slashed and non-slashed validators to calculate the slashing penalty correctly.
- An additional penalty to account for the missed rewards during slashing is introduced.
:::
#### Non-slashed validators

Once the CM v2 validator is withdrawn, the CSM/CM Bot will report it using a permissionless method. The report is submitted to the `Verifier.sol` to validate proof against `beaconBlockRoot`. If the proof is valid and the validator is not slashed, the report is bypassed to the `CuratedModule.sol`. `CuratedModule.sol` marks the validator as withdrawn. There is a separate flow for the slashed validators described below.
Suppose the validator is reported as stuck (late to exit) or ejected due to strikes (bad performance). In that case, the recorded stuck and/or bad performance penalties are applied, and the recorded TE fee is confiscated. If the validator was not reported as stuck or ejected due to bad performance, but the TE fee is recorded, the TE fee is ignored.
If the validator's balance is below 32 ETH, the difference between 32 ETH and the validator's balance is confiscated from the bond.
#### Slashed validators

If the validator is slashed, a separate flow is used. First the fact of validator slashing should be proved using `Verifier.sol`. Once slashing is proved, slashing penalty and withdrawal balance are reported usiing `EasyTrack` motion.
The rest of the flow is identical to the flow for non-slashed validators described above.
### Stuck validators ejection penalty


With its updated functionality, `VEBO` can now trigger exits (via `TWG`) for the validators requested for exit in the `VEBO` report. However, the time when requested validators can be ejected is not limited. Hence, `CuratedModule.sol` should be notified by `StakingRouter` about the validator exits and the time between the request and ejection. If the time exceeds the threshold, the Node Operator should be penalized for not exiting their validators in time. If Triggerable Exit (TE) was used for the validator, depending on the exit type and if the validator was delayed to exit, the TE fee should be confiscated from the Node Operator's bond. Both stuck penalty and TE fee are recorded in `ExitPenalties.sol` and applied upon validator withdrawal described above.
> The validator is considered "stuck" if the proof is delivered stating that it was not exited for more than `allowedExitDelay` seconds since the moment it was requested/available for exit. `allowedExitDelay` is a parameter that can be set per-Node-Operator-type.
### Node Operator addresses management
:::info
Changed in CM v2
- A dedicated role capable of changing both manager and reward adresses is added.
:::
Node Operators in CM v2 can manage their addresses like CSM Node Operators do. The main difference is that in CM v2, designated role members can change both manager and reward addresses. It is assumed that these changes are made directly by the Lido DAO via on-chain voting or by a designated emergency committee acting only if the Node Operator's `managerAddress` address is compromised and no longer reachable.
To streamline Node Operator operations, it is proposed to set extendedManagerPermissions = true for all Node Operators in CM v2. This will allow for flexibility in address management.
## Contracts specifications
TBD
## Administrative actions
Curated Module v2 contracts support a set of administrative actions, including:
- Changing the configuration options.
- Upgrading the system's code.
Each action can only be performed by a designated admin (`DEFAULT_ADMIN_ROLE`) or other role members. Only members of `DEFAULT_ADMIN_ROLE` can manage role members for the roles in CSM contracts.
## Roles to actors mapping
TBD
## Upgradability
TBD
## Security considerations
TBD