owned this note
owned this note
Published
Linked with GitHub
Early draft. WIP
--
# 📝 Community Staking Module Spec
![image](https://hackmd.io/_uploads/S1G7OO6JR.png)
The [Community Staking Landscape](https://hackmd.io/@lido/Byp775Ay6) describes the motivation for the Community Staking Module (CSM) development. A detailed description of the CSM design principles can be found in the [CSM Architecture](https://hackmd.io/@lido/rJMcGj0Ap) document. This document provides a detailed description of the technical implementation of CSM and related pieces of software, which should be considered an extension of the [CSM Architecture](https://hackmd.io/@lido/rJMcGj0Ap).
> 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
![image](https://hackmd.io/_uploads/B1KYh2RW0.png)
As depicted in the scheme above, CSM is a set of Ethereum smart contracts and off-chain tools, namely:
### Contracts
**`CSmodule.sol`** (CSM on the scheme) - a core module contract conforming to the `IStakingModule` interface. Stores information about Node Operators and deposit data (DD). This contract is used as an entry point for the Node Operators. It is responsible for all interactions with the `StakingRouter`, namely, the DD queue management and Node Operator's params.
**`CSAccounting.sol`** (Accounting in the scheme) - a supplementary contract responsible for the management of bond, rewards, and penalties. It stores bond tokens in the form of `stETH` shares, provides information about the bond required, and provides interfaces for the penalties.
**`CSVerifier.sol`** (Verifier on the scheme) - a utility contract responsible for the validation of the CL data proofs using EIP-4788. It accepts proof of the validator withdrawal and slashing events and reports these facts to the `CSModule.sol` if the proof is valid.
**`CSEarlyAdoption.sol`** (EarlyAdoption on the scheme) - a supplementary contract responsible for the Early Adoption members' verification. It validates if the address is eligible to create a Node Operator during the Early Adoption period or if the address is eligible to create a Node Operator with the discounted bond curve once the Early Adoption period is over. It stores information about eligible addresses that have already been used to create a Node Operator.
**`CSFeeDistributor.sol`** (FeeDistributor on the scheme) - a supplementary contract that stores non-claimed and non-distributed Node Operator rewards on balance and the latest root of a rewards distribution Merkle tree root. It accepts calls from `CSAccounting.sol` with reward claim requests and stores data about already claimed rewards by the Node Operator. It receives non-distributed rewards from the `CSModule.sol` each time the `StakingRouter` mints the new portion of the Node Operators' rewards.
**`CSFeeOracle.sol`** (FeeOracle on the scheme) - 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 `CSFeeDistributor.sol`, and reporting the latest root of rewards distribution Merkle tree to the `CSFeeDistributor.sol`. Inherited from the `BaseOracle.sol` from LoE.
**`HashConsensus.sol`** - a utility contract responsible for reaching consensus between CSM Oracle members. Uses the standard code of the `HashConsensus` contract from the LoE.
**`EasyTrack`** - a utility contract responsible for the application of the reported EL stealing penalties. A part of the common `EasyTrack` setup within LoE.
**`GateSeal`** - a utility contract responsible for the one-time pause of the `CSModule.sol` and `CSAccounting.sol` contracts to prevent possible exploitation of the module through zero-day vulnerability. Uses the standard code of the `GateSeal` contract from LoE.
### Off-chain tools
**`CSM Bot`** - a daemon application responsible for monitoring and reporting the withdrawal and slashing events associated with the CSM validators.
**`EL stealing detector`** - a daemon application or EOA responsible for detecting and reporting the EL stealing facts by the CSM validators. Assumed to be EOA controlled by the dev team at the early stages of the MEV monitoring software maturity and later converted to the automated bot to avoid false-positive activations.
**`CSM Oracle`** - a module in the common LoE oracle set. Operated by the existing oracles set alongside Accounting Oracle and Validator Exit Bus Oracle. It is responsible for the calculation of the CSM Node Operators' rewards distribution based on their attestation performance on the CL.
## Main flows
### Create Node Operator
![image](https://hackmd.io/_uploads/HJrHTH2JC.png)
Node Operator creation is done using `CSModule.sol`. To avoid flooding of the module with empty Node Operators, at least one deposit data and corresponding bond amount is required to create a Node Operator. Prior to Node Operator creation, a required bond amount should be fetched from the `CSAccounting.sol`. Depending on the selected token, this amount should be:
- attached as a payment to the transaction (ETH);
- approved to be transferred by `CSAccounting.sol` (stETH, wstETH);
- included in permit data approving transfers by `CSAccounting.sol` (stETH, wstETH);
### Upload deposit data
![image](https://hackmd.io/_uploads/r1_U6H2kR.png)
Node Operators can upload deposit data after Node Operator creation. Prior to uploading, the required bond amount should be fetched from `CSAccounting.sol`, and corresponding approvals, permits, or direct attachments as a payment should be performed the same way as for the [Node Operator creation](#CreateNodeOperator).
### Delete deposit data
![image](https://hackmd.io/_uploads/BJpltIp1C.png)
The node operator can request deposit data deletion if it has not been deposited yet. The Node Operator requests deposit data deletion from `CSModule.sol` to do it. `CSModule.sol` validates that deposit data has not yet been deposited. If deletion is possible `CSAccounting.sol` confiscate `deletionFee` from the Node Operator's bond.
### Top-up bond without deposit data upload
![image](https://hackmd.io/_uploads/HJv6hhAW0.png)
CSM Node Operators can top-up bond at any time to have excess bond in advance or compensate for the penalties. Top-up is done via `CSModule.sol`. Once funds are transferred to `CSAccounting.sol`, `CSModule.sol` is informed about the bond amount change and corresponding changes in the depositable keys for the Node Operator to account for it.
### Stake allocation
To determine the next portion of the validator keys to be deposited, CSM utilizes the FIFO queue. A description of the queue can be found in the [CSM Architecture](https://hackmd.io/gGRgZ0yeTnm-9SSFuHrXwg#Stake-allocation-queue) document and in a [separate spec](https://hackmd.io/@lido/ryw2Qo5ia).
#### Basic flow
![image](https://hackmd.io/_uploads/BksD6ShkR.png)
Once uploaded, deposit data is placed in the queue. To allocate stake to the CSM Node Operators, `StakingRouter` calls the [`obtainDepositData(depositsCount)`](https://github.com/lidofinance/lido-dao/blob/master/contracts/0.8.9/interfaces/IStakingModule.sol#L140) method to get the next `depositsCount` [depositable keys](https://hackmd.io/gGRgZ0yeTnm-9SSFuHrXwg#Depositable-keys) from the keys queue.
#### Invalid keys
![image](https://hackmd.io/_uploads/B1xFpr3J0.png)
Due to [optimistic vetting approach](https://hackmd.io/gGRgZ0yeTnm-9SSFuHrXwg#Deposit-data-validation-and-invalidation-aka-vetting-and-unvetting), invalid keys might be present in the queue. DSM is responsible for the detection and reporting of invalid keys through `StakingRouter`. If invalid keys are detected, a call to `decreaseOperatorVettedKeys` is expected from `StakingRouter` to `CSModule.sol`.
### Rewards distribution
![image](https://hackmd.io/_uploads/SJI9aS2JC.png)
`StakingRouter` mint rewards for CSM Node Operators on each report of the `AccountingOracle`. `CSModule.sol` bypasses minted rewards to the `CSFeeDistributor.sol`. Once the report slot is reached for the next CSM Oracle report, the rewards distribution tree is [calculated](https://hackmd.io/gGRgZ0yeTnm-9SSFuHrXwg#Performance-Oracle) by each Oracle member. After reaching the quorum, a new Merkle tree root is submitted to the `CSFeeDistributor.sol`, and the corresponding portion of the rewards is transferred from the non-distributed to the non-claimed state.
### Rewards claim
![image](https://hackmd.io/_uploads/S1Jh1SbgA.png)
Total rewards for the CSM Node Operators are comprised of [bond rewards and staking fees](https://hackmd.io/gGRgZ0yeTnm-9SSFuHrXwg#%F0%9F%A4%91-Step-2-Rewards). To claim the total rewards, the Node Operator needs to bring proof of the latest `cumulativeFeeShares` in the rewards tree. With that proof `CSAccounting.sol` pulls the Node Operator's portion of the staking fees from the `CSFeeDistributor.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.
Node Operator can transfer staking rewards to the bond without transferring it to the reward address by passing `0` as the amount requested for the claim.
If there are no new rewards to pull from the `CSFeeDistributor.sol` Node Operator can still claim excess bond using the same flow.
### EL stealing penalty
![image](https://hackmd.io/_uploads/SJ0TI8-gR.png)
If the Node Operator commits EL rewards stealing (or violates the [Lido MEV policy](https://research.lido.fi/t/discussion-draft-lido-on-ethereum-block-proposer-rewards-policy-2-0/3132/13)) the fact of stealing and stolen amount are reported to the `CSModule.sol` by the EL stealing detector actor. The corresponding amount of the bond funds is locked by the `CSAccounting.sol`. Node Operator can compensate for the stolen funds and fixed fee voluntarily. If the Node Operator does not compensate for the stolen funds, `EasyTrack` is started to confirm the penalty application. Once enacted, a penalty is applied (locked funds are burned), and the bond curve for the Node Operator is reset to the default one.
### Slashing reporting
![image](https://hackmd.io/_uploads/HyXHgUaJA.png)
If one of the CSM validators is slashed, the CSM Bot will report it. The report is submitted to the `CSVerifier.sol` to validate proof against beaconBlockRoot. If the proof is valid, the report is bypassed to the `CSModule.sol`. `CSModule.sol` marks the validator as slashed and requests bond penalization for the Node Operator by `CSAccounting.sol`.
### Withdrawal reporting
![image](https://hackmd.io/_uploads/SkhtbUpJC.png)
Once the CSM validator is withdrawn, the CSM Bot will report it. The report is submitted to the `CSVerifier.sol` to validate proof against beaconBlockRoot. If the proof is valid, the report is bypassed to the `CSModule.sol`. `CSModule.sol` marks the validator as withdrawn and requests bond penalization for the Node Operator by `CSAccounting.sol` if the withdrawal balance is lower than 32 ETH. If the withdrawn validator is slashed, the bond curve is reset to the default one for the Node Operator by `CSAccounting.sol`.
## Contracts specifications
### `CSModule.sol`
The core contract of the system. It fully implements the `IStakingModule` interface to allow system connection to the StakingRouter in a proper way.
The contract itself provides an interface for the Node Operators' creation and management. It stores the data about Node Operators and their validator keys. The keys storage system is inherited from the Curated Module. The keys queue is managed by the contract.
#### Struct: NodeOperator
``` solidity
struct NodeOperator {
address managerAddress;
address proposedManagerAddress;
address rewardAddress;
address proposedRewardAddress;
bool active;
uint256 targetLimit;
uint8 targetLimitMode;
uint256 stuckPenaltyEndTimestamp;
uint256 totalExitedKeys; // @dev only increased
uint256 totalAddedKeys; // @dev increased and decreased when removed
uint256 totalWithdrawnKeys; // @dev only increased
uint256 totalDepositedKeys; // @dev only increased
uint256 totalVettedKeys; // @dev both increased and decreased
uint256 stuckValidatorsCount; // @dev both increased and decreased
uint256 refundedValidatorsCount; // @dev only increased
uint256 depositableValidatorsCount; // @dev any value
uint256 enqueuedCount; // Tracks how many places are occupied by the node operator's keys in the queue.
}
```
Stores information about the Node Operator's parameters and state.
#### Function: resume
Resume module
```solidity
function resume() external onlyRole(RESUME_ROLE);
```
#### Function: pauseFor
Pause module for `duration` seconds
```solidity
function pauseFor(uint256 duration) external onlyRole(PAUSE_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`duration`|`uint256`|Duration of the pause in seconds|
#### Function: activatePublicRelease
Activate public release mode
Enable permissionless creation of the Node Operators
Remove the keys limit for the Node Operators
```solidity
function activatePublicRelease() external onlyRole(MODULE_MANAGER_ROLE);
```
#### Function: setKeyRemovalCharge
Set the key removal charge. A charge is taken from the bond for each removed key
```solidity
function setKeyRemovalCharge(uint256 amount) external onlyRole(MODULE_MANAGER_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`amount`|`uint256`|Amount of wei to be charged for removing a single key|
#### Function: addNodeOperatorETH
Add a new Node Operator using ETH as a bond
```solidity
function addNodeOperatorETH(
uint256 keysCount,
bytes calldata publicKeys,
bytes calldata signatures,
address managerAddress,
address rewardAddress,
bytes32[] calldata eaProof,
address referrer
) external payable whenResumed;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`keysCount`|`uint256`|Signing keys count|
|`publicKeys`|`bytes`|Public keys to submit|
|`signatures`|`bytes`|Signatures of `(deposit_message_root, domain)` tuples https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#signingdata|
|`managerAddress`|`address`|Optional. Used as `managerAddress` for the Node Operator. If not passed `msg.sender` will be used|
|`rewardAddress`|`address`|Optional. Used as `rewardAddress` for the Node Operator. If not passed `msg.sender` will be used|
|`eaProof`|`bytes32[]`|Optional. Merkle proof of the sender being eligible for the Early Adoption|
|`referrer`|`address`|Optional. Referrer address|
#### Function: addNodeOperatorStETH
Add a new Node Operator using stETH as a bond
Due to the stETH rounding issue make sure to make approval or sign permit with extra 10 wei to avoid revert
```solidity
function addNodeOperatorStETH(
uint256 keysCount,
bytes calldata publicKeys,
bytes calldata signatures,
address managerAddress,
address rewardAddress,
ICSAccounting.PermitInput calldata permit,
bytes32[] calldata eaProof,
address referrer
) external whenResumed;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`keysCount`|`uint256`|Signing keys count|
|`publicKeys`|`bytes`|Public keys to submit|
|`signatures`|`bytes`|Signatures of `(deposit_message_root, domain)` tuples https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#signingdata|
|`managerAddress`|`address`|Optional. Used as `managerAddress` for the Node Operator. If not passed `msg.sender` will be used|
|`rewardAddress`|`address`|Optional. Used as `rewardAddress` for the Node Operator. If not passed `msg.sender` will be used|
|`permit`|`ICSAccounting.PermitInput`|Optional. Permit to use stETH as bond|
|`eaProof`|`bytes32[]`|Optional. Merkle proof of the sender being eligible for the Early Adoption|
|`referrer`|`address`|Optional, Referrer address|
#### Function: addNodeOperatorWstETH
Add a new Node Operator using wstETH as a bond
Due to the stETH rounding issue make sure to make approval or sign permit with extra 10 wei to avoid revert
```solidity
function addNodeOperatorWstETH(
uint256 keysCount,
bytes calldata publicKeys,
bytes calldata signatures,
address managerAddress,
address rewardAddress,
ICSAccounting.PermitInput calldata permit,
bytes32[] calldata eaProof,
address referrer
) external whenResumed;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`keysCount`|`uint256`|Signing keys count|
|`publicKeys`|`bytes`|Public keys to submit|
|`signatures`|`bytes`|Signatures of `(deposit_message_root, domain)` tuples https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#signingdata|
|`managerAddress`|`address`|Optional. Used as `managerAddress` for the Node Operator. If not passed `msg.sender` will be used|
|`rewardAddress`|`address`|Optional. Used as `rewardAddress` for the Node Operator. If not passed `msg.sender` will be used|
|`permit`|`ICSAccounting.PermitInput`|Optional. Permit to use wstETH as bond|
|`eaProof`|`bytes32[]`|Optional. Merkle proof of the sender being eligible for the Early Adoption|
|`referrer`|`address`|Optional. Referrer address|
#### Function: addValidatorKeysETH
Add new keys to the Node Operator using ETH as a bond
```solidity
function addValidatorKeysETH(
uint256 nodeOperatorId,
uint256 keysCount,
bytes calldata publicKeys,
bytes calldata signatures
) external payable whenResumed;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`keysCount`|`uint256`|Signing keys count|
|`publicKeys`|`bytes`|Public keys to submit|
|`signatures`|`bytes`|Signatures of `(deposit_message_root, domain)` tuples https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#signingdata|
#### Function: addValidatorKeysStETH
Add new keys to the Node Operator using stETH as a bond
Due to the stETH rounding issue make sure to make approval or sign permit with extra 10 wei to avoid revert
```solidity
function addValidatorKeysStETH(
uint256 nodeOperatorId,
uint256 keysCount,
bytes calldata publicKeys,
bytes calldata signatures,
ICSAccounting.PermitInput calldata permit
) external whenResumed;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`keysCount`|`uint256`|Signing keys count|
|`publicKeys`|`bytes`|Public keys to submit|
|`signatures`|`bytes`|Signatures of `(deposit_message_root, domain)` tuples https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#signingdata|
|`permit`|`ICSAccounting.PermitInput`|Optional. Permit to use stETH as bond|
#### Function: addValidatorKeysWstETH
Add new keys to the Node Operator using wstETH as a bond
Due to the stETH rounding issue make sure to make approval or sign permit with extra 10 wei to avoid revert
```solidity
function addValidatorKeysWstETH(
uint256 nodeOperatorId,
uint256 keysCount,
bytes calldata publicKeys,
bytes calldata signatures,
ICSAccounting.PermitInput calldata permit
) external whenResumed;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`keysCount`|`uint256`|Signing keys count|
|`publicKeys`|`bytes`|Public keys to submit|
|`signatures`|`bytes`|Signatures of `(deposit_message_root, domain)` tuples https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#signingdata|
|`permit`|`ICSAccounting.PermitInput`|Optional. Permit to use wstETH as bond|
#### Function: depositETH
Stake user's ETH to Lido and make a deposit in stETH to the bond
```solidity
function depositETH(uint256 nodeOperatorId) external payable;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
#### Function: depositStETH
Deposit user's stETH to the bond for the given Node Operator
```solidity
function depositStETH(uint256 nodeOperatorId, uint256 stETHAmount, ICSAccounting.PermitInput calldata permit)
external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`stETHAmount`|`uint256`|Amount of stETH to deposit|
|`permit`|`ICSAccounting.PermitInput`|Optional. Permit to use stETH as bond|
#### Function: depositWstETH
Unwrap the user's wstETH and make a deposit in stETH to the bond for the given Node Operator
```solidity
function depositWstETH(uint256 nodeOperatorId, uint256 wstETHAmount, ICSAccounting.PermitInput calldata permit)
external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`wstETHAmount`|`uint256`|Amount of wstETH to deposit|
|`permit`|`ICSAccounting.PermitInput`|Optional. Permit to use wstETH as bond|
#### Function: claimRewardsStETH
Claim full reward (fees + bond rewards) in stETH for the given Node Operator
If `stETHAmount` exceeds the current claimable amount, the claimable amount will be used instead
If `rewardsProof` is not provided, only excess bond will be available for claim
```solidity
function claimRewardsStETH(
uint256 nodeOperatorId,
uint256 stETHAmount,
uint256 cumulativeFeeShares,
bytes32[] memory rewardsProof
) external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`stETHAmount`|`uint256`|Amount of stETH to claim|
|`cumulativeFeeShares`|`uint256`|Optional. Cumulative fee stETH shares for the Node Operator|
|`rewardsProof`|`bytes32[]`|Optional. Merkle proof of the rewards|
#### Function: claimRewardsWstETH
Claim full reward (fees + bond rewards) in цstETH for the given Node Operator
If `wstETHAmount` exceeds the current claimable amount, the claimable amount will be used instead
If `rewardsProof` is not provided, only excess bond will be available for claim
```solidity
function claimRewardsWstETH(
uint256 nodeOperatorId,
uint256 wstETHAmount,
uint256 cumulativeFeeShares,
bytes32[] memory rewardsProof
) external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`wstETHAmount`|`uint256`|Amount of wstETH to claim|
|`cumulativeFeeShares`|`uint256`|Optional. Cumulative fee stETH shares for the Node Operator|
|`rewardsProof`|`bytes32[]`|Optional. Merkle proof of the rewards|
#### Function: requestRewardsETH
Request full reward (fees + bond rewards) in Withdrawal NFT (unstETH) for the given Node Operator
Amounts less than `MIN_STETH_WITHDRAWAL_AMOUNT` (see LidoWithdrawalQueue contract) are not allowed
Amounts above `MAX_STETH_WITHDRAWAL_AMOUNT` should be requested in several transactions
If `ethAmount` exceeds the current claimable amount, the claimable amount will be used instead
If `rewardsProof` is not provided, only excess bond will be available for claim
*Reverts if amount isn't between `MIN_STETH_WITHDRAWAL_AMOUNT` and `MAX_STETH_WITHDRAWAL_AMOUNT`*
```solidity
function requestRewardsETH(
uint256 nodeOperatorId,
uint256 ethAmount,
uint256 cumulativeFeeShares,
bytes32[] memory rewardsProof
) external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`ethAmount`|`uint256`|Amount of ETH to request|
|`cumulativeFeeShares`|`uint256`|Optional. Cumulative fee stETH shares for the Node Operator|
|`rewardsProof`|`bytes32[]`|Optional. Merkle proof of the rewards|
#### Function: proposeNodeOperatorManagerAddressChange
Propose a new manager address for the Node Operator
```solidity
function proposeNodeOperatorManagerAddressChange(uint256 nodeOperatorId, address proposedAddress) external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`proposedAddress`|`address`|Proposed manager address|
#### Function: confirmNodeOperatorManagerAddressChange
Confirm a new manager address for the Node Operator
```solidity
function confirmNodeOperatorManagerAddressChange(uint256 nodeOperatorId) external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
#### Function: proposeNodeOperatorRewardAddressChange
Propose a new reward address for the Node Operator
```solidity
function proposeNodeOperatorRewardAddressChange(uint256 nodeOperatorId, address proposedAddress) external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`proposedAddress`|`address`|Proposed reward address|
#### Function: confirmNodeOperatorRewardAddressChange
Confirm a new reward address for the Node Operator
```solidity
function confirmNodeOperatorRewardAddressChange(uint256 nodeOperatorId) external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
#### Function: resetNodeOperatorManagerAddress
Reset the manager address to the reward address
```solidity
function resetNodeOperatorManagerAddress(uint256 nodeOperatorId) external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
#### Function: onRewardsMinted
Called when rewards are minted for the module
*Passes through the minted stETH shares to the fee distributor*
```solidity
function onRewardsMinted(uint256 totalShares) external onlyRole(STAKING_ROUTER_ROLE);
```
#### Function: updateStuckValidatorsCount
Update stuck validators count for Node Operators
*Called by StakingRouter*
*If the stuck keys count is above zero for the Node Operator,
the depositable validators count is set to 0 for this Node Operator*
```solidity
function updateStuckValidatorsCount(bytes calldata nodeOperatorIds, bytes calldata stuckValidatorsCounts)
external
onlyRole(STAKING_ROUTER_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorIds`|`bytes`|bytes packed array of Node Operator IDs|
|`stuckValidatorsCounts`|`bytes`|bytes packed array of stuck validators counts|
#### Function: updateExitedValidatorsCount
Updates exited validators count for Node Operators
*Called by StakingRouter*
```solidity
function updateExitedValidatorsCount(bytes calldata nodeOperatorIds, bytes calldata exitedValidatorsCounts)
external
onlyRole(STAKING_ROUTER_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorIds`|`bytes`|bytes packed array of Node Operator IDs|
|`exitedValidatorsCounts`|`bytes`|bytes packed array of exited validators counts|
#### Function: updateRefundedValidatorsCount
Update refunded validators count for the Node Operator
*Called by StakingRouter*
*`refundedValidatorsCount` is not used in the module*
```solidity
function updateRefundedValidatorsCount(uint256 nodeOperatorId, uint256 refundedValidatorsCount)
external
onlyRole(STAKING_ROUTER_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`refundedValidatorsCount`|`uint256`|Number of refunded validators|
#### Function: updateTargetValidatorsLimits
Update target limits for Node Operator
*Called by StakingRouter*
```solidity
function updateTargetValidatorsLimits(uint256 nodeOperatorId, uint8 targetLimitMode, uint256 targetLimit)
external
onlyRole(STAKING_ROUTER_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`targetLimitMode`|`uint8`|Target limit mode for the Node Operator 0 - disabled 1 - soft mode 2 - forced mode|
|`targetLimit`|`uint256`|Target limit of validators|
#### Function: onExitedAndStuckValidatorsCountsUpdated
Called by the Staking Router when exited and stuck validators counts updated
```solidity
function onExitedAndStuckValidatorsCountsUpdated() external onlyRole(STAKING_ROUTER_ROLE);
```
#### Function: unsafeUpdateValidatorsCount
Unsafe update of validators count for Node Operators by DAO
Called by Staking Router
```solidity
function unsafeUpdateValidatorsCount(
uint256 nodeOperatorId,
uint256 exitedValidatorsKeysCount,
uint256 stuckValidatorsKeysCount
) external onlyRole(STAKING_ROUTER_ROLE);
```
#### Function: decreaseOperatorVettedKeys
Decrease totalVettedKeys for the Node Operator
Called by Staking Router
```solidity
function decreaseOperatorVettedKeys(uint256[] calldata nodeOperatorIds, uint256[] calldata vettedKeysByOperator)
external
onlyRole(STAKING_ROUTER_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorIds`|`uint256[]`|IDs of the Node Operators to decrease totalVettedKeys for|
|`vettedKeysByOperator`|`uint256[]`|Corresponding values for totalVettedKeys decrease|
#### Function: removeKeys
Remove keys for the Node Operator and confiscate removal charge for each deleted key
```solidity
function removeKeys(uint256 nodeOperatorId, uint256 startIndex, uint256 keysCount) external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`startIndex`|`uint256`|Index of the first key|
|`keysCount`|`uint256`|Keys count to delete|
#### Function: normalizeQueue
Perform queue normalization for the given Node Operator
Normalization stands for adding vetted but not enqueued keys to the queue
```solidity
function normalizeQueue(uint256 nodeOperatorId) external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
#### Function: reportELRewardsStealingPenalty
Report EL rewards stealing for the given Node Operator
The amount equal to the stolen funds plus EL stealing fine will be locked
```solidity
function reportELRewardsStealingPenalty(uint256 nodeOperatorId, bytes32 blockHash, uint256 amount)
external
onlyRole(REPORT_EL_REWARDS_STEALING_PENALTY_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`blockHash`|`bytes32`|Execution layer block hash of the proposed block with EL rewards stealing|
|`amount`|`uint256`|Amount of stolen EL rewards in ETH|
#### Function: cancelELRewardsStealingPenalty
Cancel previously reported and not settled EL rewards stealing penalty for the given Node Operator
The funds will be unlocked
```solidity
function cancelELRewardsStealingPenalty(uint256 nodeOperatorId, uint256 amount)
external
onlyRole(REPORT_EL_REWARDS_STEALING_PENALTY_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`amount`|`uint256`|Amount of penalty to cancel|
#### Function: settleELRewardsStealingPenalty
Settles blocked bond for the given Node Operators
*Should be called by the Easy Track*
```solidity
function settleELRewardsStealingPenalty(uint256[] memory nodeOperatorIds)
external
onlyRole(SETTLE_EL_REWARDS_STEALING_PENALTY_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorIds`|`uint256[]`|IDs of the Node Operators|
#### Function: compensateELRewardsStealingPenalty
Compensate EL rewards stealing penalty for the given Node Operator to prevent further validator exits
*Expected to be called by the Node Operator, but can be called by anyone*
```solidity
function compensateELRewardsStealingPenalty(uint256 nodeOperatorId) external payable;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
#### Function: submitWithdrawal
Report Node Operator's key as withdrawn and settle withdrawn amount
Called by the Verifier contract.
See `CSVerifier.processWithdrawalProof` to use this method permissionless
```solidity
function submitWithdrawal(uint256 nodeOperatorId, uint256 keyIndex, uint256 amount) external onlyRole(VERIFIER_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`keyIndex`|`uint256`|Index of the withdrawn key in the Node Operator's keys storage|
|`amount`|`uint256`|Amount of withdrawn ETH in wei|
#### Function: submitInitialSlashing
Report Node Operator's key as slashed and apply the initial slashing penalty
Called by the Verifier contract.
See `CSVerifier.processSlashingProof` to use this method permissionless
```solidity
function submitInitialSlashing(uint256 nodeOperatorId, uint256 keyIndex) external onlyRole(VERIFIER_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`keyIndex`|`uint256`|Index of the slashed key in the Node Operator's keys storage|
#### Function: onWithdrawalCredentialsChanged
Called by the Staking Router when withdrawal credentials changed by DAO
*Resets the key removal charge*
*Changing the WC means that the current deposit data in the queue is not valid anymore and can't be deposited
So, the key removal charge should be reset to 0 to allow Node Operators to remove the keys without any charge.
After keys removal the DAO should set the new key removal charge.*
```solidity
function onWithdrawalCredentialsChanged() external onlyRole(STAKING_ROUTER_ROLE);
```
#### Function: obtainDepositData
Get the next `depositsCount` of depositable keys with signatures from the queue
*Second param `depositCalldata` is not used*
```solidity
function obtainDepositData(uint256 depositsCount, bytes calldata)
external
onlyRole(STAKING_ROUTER_ROLE)
returns (bytes memory publicKeys, bytes memory signatures);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`depositsCount`|`uint256`|Count of deposits to get|
|`<none>`|`bytes`||
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`publicKeys`|`bytes`|Public keys|
|`signatures`|`bytes`|Signatures|
#### Function: cleanDepositQueue
Clean the deposit queue from batches with no depositable keys
*Use **eth_call** to check how many items will be removed*
```solidity
function cleanDepositQueue(uint256 maxItems) external returns (uint256 toRemove);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`maxItems`|`uint256`|How many queue items to review|
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`toRemove`|`uint256`|Number of the deposit data removed from the queue|
#### Function: recoverStETHShares
Recover all stETH shares from the contract
*There should be no stETH shares on the contract balance during regular operation*
```solidity
function recoverStETHShares() external;
```
#### Function: depositQueueItem
Get the deposit queue item by an index
```solidity
function depositQueueItem(uint128 index) external view returns (Batch item);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`index`|`uint128`|Index of a queue item|
#### Function: isValidatorSlashed
Check if the given Node Operator's key is reported as slashed
```solidity
function isValidatorSlashed(uint256 nodeOperatorId, uint256 keyIndex) external view returns (bool);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`keyIndex`|`uint256`|Index of the key to check|
#### Function: isValidatorWithdrawn
Check if the given Node Operator's key is reported as withdrawn
```solidity
function isValidatorWithdrawn(uint256 nodeOperatorId, uint256 keyIndex) external view returns (bool);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`keyIndex`|`uint256`|index of the key to check|
#### Function: getType
Get the module type
```solidity
function getType() external view returns (bytes32);
```
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`<none>`|`bytes32`|Module type|
#### Function: getStakingModuleSummary
Get staking module summary
```solidity
function getStakingModuleSummary() external view returns (uint256, uint256, uint256);
```
#### Function: getNodeOperator
Get Node Operator info
```solidity
function getNodeOperator(uint256 nodeOperatorId) external view returns (NodeOperator memory);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`<none>`|`NodeOperator`|Node Operator info|
#### Function: getNodeOperatorNonWithdrawnKeys
Get Node Operator non-withdrawn keys
```solidity
function getNodeOperatorNonWithdrawnKeys(uint256 nodeOperatorId) external view returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`<none>`|`uint256`|Non-withdrawn keys count|
#### Function: getNodeOperatorRewardAddress
Get Node Operator reward address
```solidity
function getNodeOperatorRewardAddress(uint256 nodeOperatorId) external view returns (address);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`<none>`|`address`|Reward address|
#### Function: getNodeOperatorSummary
Get Node Operator summary
depositableValidatorsCount depends on:
- totalVettedKeys
- totalDepositedKeys
- totalExitedKeys
- targetLimitMode
- targetValidatorsCount
- totalunbondedKeys
- totalStuckKeys
```solidity
function getNodeOperatorSummary(uint256 nodeOperatorId)
external
view
returns (
uint8 targetLimitMode,
uint256 targetValidatorsCount,
uint256 stuckValidatorsCount,
uint256 refundedValidatorsCount,
uint256 stuckPenaltyEndTimestamp,
uint256 totalExitedValidators,
uint256 totalDepositedValidators,
uint256 depositableValidatorsCount
);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`targetLimitMode`|`uint8`|Target limit mode|
|`targetValidatorsCount`|`uint256`|Target validators count|
|`stuckValidatorsCount`|`uint256`|Stuck validators count|
|`refundedValidatorsCount`|`uint256`|Refunded validators count|
|`stuckPenaltyEndTimestamp`|`uint256`|Stuck penalty end timestamp|
|`totalExitedValidators`|`uint256`|Total exited validators|
|`totalDepositedValidators`|`uint256`|Total deposited validators|
|`depositableValidatorsCount`|`uint256`|Depositable validators count|
#### Function: getSigningKeys
Get Node Operator signing keys
```solidity
function getSigningKeys(uint256 nodeOperatorId, uint256 startIndex, uint256 keysCount)
external
view
returns (bytes memory);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`startIndex`|`uint256`|Index of the first key|
|`keysCount`|`uint256`|Count of keys to get|
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`<none>`|`bytes`|Signing keys|
#### Function: getSigningKeysWithSignatures
Get Node Operator signing keys with signatures
```solidity
function getSigningKeysWithSignatures(uint256 nodeOperatorId, uint256 startIndex, uint256 keysCount)
external
view
returns (bytes memory keys, bytes memory signatures);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`startIndex`|`uint256`|Index of the first key|
|`keysCount`|`uint256`|Count of keys to get|
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`keys`|`bytes`|Signing keys|
|`signatures`|`bytes`|Signatures of `(deposit_message_root, domain)` tuples https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#signingdata|
#### Function: getNonce
Get nonce of the module
```solidity
function getNonce() external view returns (uint256);
```
#### Function: getNodeOperatorsCount
Get total number of Node Operators
```solidity
function getNodeOperatorsCount() external view returns (uint256);
```
#### Function: getActiveNodeOperatorsCount
Get total number of active Node Operators
```solidity
function getActiveNodeOperatorsCount() external view returns (uint256);
```
#### Function: getNodeOperatorIsActive
Get Node Operator active status
```solidity
function getNodeOperatorIsActive(uint256 nodeOperatorId) external view returns (bool);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
#### Function: getNodeOperatorIds
Get IDs of Node Operators
```solidity
function getNodeOperatorIds(uint256 offset, uint256 limit) external view returns (uint256[] memory nodeOperatorIds);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`offset`|`uint256`|Offset of the first Node Operator ID to get|
|`limit`|`uint256`|Count of Node Operator IDs to get|
### `CSAccounting.sol`
#### Function: resume
Resume accounting
```solidity
function resume() external onlyRole(RESUME_ROLE);
```
#### Function: pauseFor
Pause accounting for `duration` seconds
*Must be called together with `CSModule.pauseFor`*
```solidity
function pauseFor(uint256 duration) external onlyRole(PAUSE_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`duration`|`uint256`|Duration of the pause in seconds|
#### Function: setChargeRecipient
Set charge recipient address
```solidity
function setChargeRecipient(address _chargeRecipient) external onlyRole(ACCOUNTING_MANAGER_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`_chargeRecipient`|`address`|Charge recipient address|
#### Function: setLockedBondRetentionPeriod
Set bond lock retention period
```solidity
function setLockedBondRetentionPeriod(uint256 retention) external onlyRole(ACCOUNTING_MANAGER_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`retention`|`uint256`|Period in seconds to retain bond lock|
#### Function: addBondCurve
Add a new bond curve
```solidity
function addBondCurve(uint256[] memory bondCurve) external onlyRole(ADD_BOND_CURVE_ROLE) returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`bondCurve`|`uint256[]`|Bond curve definition to add|
#### Function: setDefaultBondCurve
Set default bond curve
```solidity
function setDefaultBondCurve(uint256 curveId) external onlyRole(SET_DEFAULT_BOND_CURVE_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`curveId`|`uint256`|ID of the bond curve to set as default|
#### Function: setBondCurve
Set the bond curve for the given Node Operator
```solidity
function setBondCurve(uint256 nodeOperatorId, uint256 curveId) external onlyRole(SET_BOND_CURVE_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`curveId`|`uint256`|ID of the bond curve to set|
#### Function: resetBondCurve
Reset bond curve to the default one for the given Node Operator
```solidity
function resetBondCurve(uint256 nodeOperatorId) external onlyRole(RESET_BOND_CURVE_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
#### Function: depositETH
Stake user's ETH with Lido and deposit stETH to the bond
*Сalled by CSM exclusively*
```solidity
function depositETH(address from, uint256 nodeOperatorId)
external
payable
whenResumed
onlyCSM
returns (uint256 shares);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`from`|`address`|Address to stake ETH and deposit stETH from|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`shares`|`uint256`|stETH shares amount|
#### Function: depositStETH
Deposit user's stETH to the bond for the given Node Operator
*Сalled by CSM exclusively*
```solidity
function depositStETH(address from, uint256 nodeOperatorId, uint256 stETHAmount, PermitInput calldata permit)
external
whenResumed
onlyCSM
returns (uint256 shares);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`from`|`address`|Address to deposit stETH from|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`stETHAmount`|`uint256`|Amount of stETH to deposit|
|`permit`|`PermitInput`|stETH permit for the contract|
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`shares`|`uint256`|stETH shares amount|
#### Function: depositWstETH
Unwrap the user's wstETH and deposit stETH to the bond for the given Node Operator
*Сalled by CSM exclusively*
```solidity
function depositWstETH(address from, uint256 nodeOperatorId, uint256 wstETHAmount, PermitInput calldata permit)
external
whenResumed
onlyCSM
returns (uint256 shares);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`from`|`address`|Address to unwrap wstETH from|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`wstETHAmount`|`uint256`|Amount of wstETH to deposit|
|`permit`|`PermitInput`|wstETH permit for the contract|
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`shares`|`uint256`|stETH shares amount|
#### Function: claimRewardsStETH
Claim full reward (fee + bond) in stETH for the given Node Operator with desirable value.
`rewardsProof` and `cumulativeFeeShares` might be empty in order to claim only excess bond
*Сalled by CSM exclusively*
```solidity
function claimRewardsStETH(
uint256 nodeOperatorId,
uint256 stETHAmount,
uint256 cumulativeFeeShares,
bytes32[] memory rewardsProof
) external whenResumed onlyCSM;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`stETHAmount`|`uint256`|Amount of stETH to claim|
|`cumulativeFeeShares`|`uint256`|Cumulative fee stETH shares for the Node Operator|
|`rewardsProof`|`bytes32[]`|Merkle proof of the rewards|
#### Function: claimRewardsWstETH
Claim full reward (fee + bond) in wstETH for the given Node Operator available for this moment.
`rewardsProof` and `cumulativeFeeShares` might be empty in order to claim only excess bond
*Сalled by CSM exclusively*
```solidity
function claimRewardsWstETH(
uint256 nodeOperatorId,
uint256 wstETHAmount,
uint256 cumulativeFeeShares,
bytes32[] memory rewardsProof
) external whenResumed onlyCSM;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`wstETHAmount`|`uint256`|Amount of wstETH to claim|
|`cumulativeFeeShares`|`uint256`|Cumulative fee stETH shares for the Node Operator|
|`rewardsProof`|`bytes32[]`|Merkle proof of the rewards|
#### Function: requestRewardsETH
Request full reward (fee + bond) in Withdrawal NFT (unstETH) for the given Node Operator available for this moment.
`rewardsProof` and `cumulativeFeeShares` might be empty in order to claim only excess bond
*Reverts if amount isn't between `MIN_STETH_WITHDRAWAL_AMOUNT` and `MAX_STETH_WITHDRAWAL_AMOUNT`*
*Сalled by CSM exclusively*
```solidity
function requestRewardsETH(
uint256 nodeOperatorId,
uint256 ethAmount,
uint256 cumulativeFeeShares,
bytes32[] memory rewardsProof
) external whenResumed onlyCSM;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`ethAmount`|`uint256`|Amount of ETH to request|
|`cumulativeFeeShares`|`uint256`|Cumulative fee stETH shares for the Node Operator|
|`rewardsProof`|`bytes32[]`|Merkle proof of the rewards|
#### Function: lockBondETH
Lock bond in ETH for the given Node Operator
*Сalled by CSM exclusively*
```solidity
function lockBondETH(uint256 nodeOperatorId, uint256 amount) external onlyCSM;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`amount`|`uint256`|Amount to lock in ETH (stETH)|
#### Function: releaseLockedBondETH
Release locked bond in ETH for the given Node Operator
*Сalled by CSM exclusively*
```solidity
function releaseLockedBondETH(uint256 nodeOperatorId, uint256 amount) external onlyCSM;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`amount`|`uint256`|Amount to release in ETH (stETH)|
#### Function: compensateLockedBondETH
Compensate locked bond ETH for the given Node Operator
```solidity
function compensateLockedBondETH(uint256 nodeOperatorId) external payable onlyCSM;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
#### Function: settleLockedBondETH
Settle locked bond ETH for the given Node Operator
*Сalled by CSM exclusively*
```solidity
function settleLockedBondETH(uint256 nodeOperatorId) external onlyCSM returns (uint256 lockedAmount);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
#### Function: penalize
Penalize bond by burning stETH shares of the given Node Operator
*Сalled by CSM exclusively*
```solidity
function penalize(uint256 nodeOperatorId, uint256 amount) external onlyCSM;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`amount`|`uint256`|Amount to penalize in ETH (stETH)|
#### Function: chargeFee
Charge fee from bond by transferring stETH shares of the given Node Operator to the charge recipient
*Сalled by CSM exclusively*
```solidity
function chargeFee(uint256 nodeOperatorId, uint256 amount) external onlyCSM;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`amount`|`uint256`|Amount to charge in ETH (stETH)|
#### Function: recoverERC20
Recover ERC20 tokens from the contract
```solidity
function recoverERC20(address token, uint256 amount) external override;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`token`|`address`|Address of the ERC20 token to recover|
|`amount`|`uint256`|Amount of the ERC20 token to recover|
#### Function: recoverStETHShares
Recover all stETH shares from the contract
*Accounts for the bond funds stored during recovery*
```solidity
function recoverStETHShares() external;
```
#### Function: getBondSummary
Get current and required bond amounts in ETH (stETH) for the given Node Operator
*To calculate excess bond amount subtract `required` from `current` value.
To calculate missed bond amount subtract `current` from `required` value*
```solidity
function getBondSummary(uint256 nodeOperatorId) public view returns (uint256 current, uint256 required);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`current`|`uint256`|Current bond amount in ETH|
|`required`|`uint256`|Required bond amount in ETH|
#### Function: getBondSummaryShares
Get current and required bond amounts in stETH shares for the given Node Operator
*To calculate excess bond amount subtract `required` from `current` value.
To calculate missed bond amount subtract `current` from `required` value*
```solidity
function getBondSummaryShares(uint256 nodeOperatorId) public view returns (uint256 current, uint256 required);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`current`|`uint256`|Current bond amount in stETH shares|
|`required`|`uint256`|Required bond amount in stETH shares|
#### Function: getUnbondedKeysCount
Get the number of the unbonded keys
```solidity
function getUnbondedKeysCount(uint256 nodeOperatorId) public view returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
**Returns**
| Name | Type | Description |
| -------- | --------- | ------------------- |
| `<none>` | `uint256` Unbonded keys count nt |
#### Function: getUnbondedKeysCountToEject
Get the number of the unbonded keys to be ejected using a forcedTargetLimit
```solidity
function getUnbondedKeysCountToEject(uint256 nodeOperatorId) public view returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
**Returns**
| Name | Type | Description |
| -------- | --------- | ------------------- |
| `<none>` | `uint256` Unbonded keys count nt |
#### Function: getRequiredBondForNextKeys
Get the required bond in ETH (inc. missed and excess) for the given Node Operator to upload new deposit data
```solidity
function getRequiredBondForNextKeys(uint256 nodeOperatorId, uint256 additionalKeys) public view returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`additionalKeys`|`uint256`|Number of new keys to add|
**Returns**
| Name | Type | Description |
| -------- | --------- | --------------------------- |
| `<none>` | `uint256` Required bond amount in ETH TH |
#### Function: getBondAmountByKeysCountWstETH
Get the bond amount in wstETH required for the `keysCount` keys using the default bond curve
```solidity
function getBondAmountByKeysCountWstETH(uint256 keysCount) public view returns (uint256);
```
**Parameters**
| Name | Type | Description |
| ----------- | --------- | ------------------------------------------------ |
| `keysCount` | `uint256` | Keys count to calculate the required bond amount |
#### Function: getBondAmountByKeysCountWstETH
Get the bond amount in wstETH required for the `keysCount` keys using the custom bond curve
```solidity
function getBondAmountByKeysCountWstETH(uint256 keysCount, BondCurve memory curve) public view returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`keysCount`|`uint256`|Keys count to calculate the required bond amount|
|`curve`|`BondCurve`|Bond curve definition. Use CSBondCurve.getBondCurve(id) method to get the definition for the exiting curve|
#### Function: getRequiredBondForNextKeysWstETH
Get the required bond in wstETH (inc. missed and excess) for the given Node Operator to upload new keys
```solidity
function getRequiredBondForNextKeysWstETH(uint256 nodeOperatorId, uint256 additionalKeys)
public
view
returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`additionalKeys`|`uint256`|Number of new keys to add|
**Returns**
| Name | Type | Description |
| -------- | --------- | ----------------------- |
| `<none>` | `uint256` Required bond in wstETH TH |
#### Function: totalBondShares
Get total bond shares (stETH) stored on the contract
```solidity
function totalBondShares() public view returns (uint256);
```
**Returns**
| Name | Type | Description |
| -------- | --------- | ------------------------- |
| `<none>` | `uint256` Total bond shares (stETH) H) |
#### Function: getBondShares
Get bond shares (stETH) for the given Node Operator
```solidity
function getBondShares(uint256 nodeOperatorId) public view returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
**Returns**
| Name | Type | Description |
| -------- | --------- | -------------------- |
| `<none>` | `uint256` Bond in stETH shares es |
#### Function: getBond
Get bond amount in ETH (stETH) for the given Node Operator
```solidity
function getBond(uint256 nodeOperatorId) public view returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
**Returns**
| Name | Type | Description |
| -------- | --------- | -------------------------- |
| `<none>` | `uint256` Bond amount in ETH (stETH) H) |
#### Function: defaultBondCurveId
```solidity
function defaultBondCurveId() public view returns (uint256);
```
#### Function: getCurveInfo
Return bond curve for the given curve id
*Get default bond curve info if `curveId` is `0` or invalid*
```solidity
function getCurveInfo(uint256 curveId) public view returns (BondCurve memory);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`curveId`|`uint256`|Curve id to get bond curve for|
**Returns**
| Name | Type | Description |
| -------- | ----------- | ----------- |
| `<none>` | `BondCurve` | Bond curve |
#### Function: getBondCurve
Get bond curve for the given Node Operator
```solidity
function getBondCurve(uint256 nodeOperatorId) public view returns (BondCurve memory);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
**Returns**
| Name | Type | Description |
| -------- | ----------- | ----------- |
| `<none>` | `BondCurve` | Bond curve |
#### Function: getBondAmountByKeysCount
Get required bond in ETH for the given number of keys for default bond curve
*To calculate the amount for the new keys 2 calls are required:
getBondAmountByKeysCount(newTotal) - getBondAmountByKeysCount(currentTotal)*
```solidity
function getBondAmountByKeysCount(uint256 keys) public view returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`keys`|`uint256`|Number of keys to get required bond for|
**Returns**
| Name | Type | Description |
| -------- | --------- | -------------------------------- |
| `<none>` | `uint256` Amount for particular keys count nt |
#### Function: getKeysCountByBondAmount
Get keys count for the given bond amount with default bond curve
```solidity
function getKeysCountByBondAmount(uint256 amount) public view returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`amount`|`uint256`|Bond amount in ETH (stETH)to get keys count for|
**Returns**
| Name | Type | Description |
| -------- | --------- | ----------- |
| `<none>` | `uint256` | Keys count |
#### Function: getBondAmountByKeysCount
Get required bond in ETH for the given number of keys for particular bond curve.
*To calculate the amount for the new keys 2 calls are required:
getBondAmountByKeysCount(newTotal, curve) - getBondAmountByKeysCount(currentTotal, curve)*
```solidity
function getBondAmountByKeysCount(uint256 keys, BondCurve memory curve) public pure returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`keys`|`uint256`|Number of keys to get required bond for|
|`curve`|`BondCurve`|Bond curve to get required bond for|
**Returns**
| Name | Type | Description |
| -------- | --------- | ------------------------------------------------------------- |
| `<none>` | `uint256` Required bond amount in ETH (stETH) for particular keys count nt |
#### Function: getKeysCountByBondAmount
Get keys count for the given bond amount for particular bond curve.
```solidity
function getKeysCountByBondAmount(uint256 amount, BondCurve memory curve) public pure returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`amount`|`uint256`|Bond amount to get keys count for|
|`curve`|`BondCurve`|Bond curve to get keys count for|
**Returns**
| Name | Type | Description |
| -------- | --------- | ----------- |
| `<none>` | `uint256` | Keys count |
#### Function: getBondLockRetentionPeriod
Get default bond lock retention period
```solidity
function getBondLockRetentionPeriod() external view returns (uint256 retention);
```
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`retention`|`uint256`|Default bond lock retention period|
#### Function: getLockedBondInfo
Get information about the locked bond for the given Node Operator
```solidity
function getLockedBondInfo(uint256 nodeOperatorId) public view returns (BondLock memory);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
**Returns**
| Name | Type | Description |
| -------- | ---------- | ---------------- |
| `<none>` | `BondLock` Locked bond info fo |
#### Function: getActualLockedBond
Get amount of the locked bond in ETH (stETH) by the given Node Operator
```solidity
function getActualLockedBond(uint256 nodeOperatorId) public view returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
**Returns**
| Name | Type | Description |
| -------- | --------- | -------------------------------- |
| `<none>` | `uint256` Amount of the actual locked bond nd |
### `CSVerifier.sol`
#### Function: processSlashingProof
Verify slashing proof and report slashing to the module for valid proofs
```solidity
function processSlashingProof(
ProvableBeaconBlockHeader calldata beaconBlock,
SlashingWitness calldata witness,
uint256 nodeOperatorId,
uint256 keyIndex
) external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`beaconBlock`|`ProvableBeaconBlockHeader`|Beacon block header|
|`witness`|`SlashingWitness`|Slashing witness|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`keyIndex`|`uint256`|Index of the validator key in the Node Operator's key storage|
#### Function: processWithdrawalProof
Verify withdrawal proof and report withdrawal to the module for valid proofs
```solidity
function processWithdrawalProof(
ProvableBeaconBlockHeader calldata beaconBlock,
WithdrawalWitness calldata witness,
uint256 nodeOperatorId,
uint256 keyIndex
) external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`beaconBlock`|`ProvableBeaconBlockHeader`|Beacon block header|
|`witness`|`WithdrawalWitness`|Withdrawal witness|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`keyIndex`|`uint256`|Index of the validator key in the Node Operator's key storage|
#### Function: processHistoricalWithdrawalProof
Verify withdrawal proof against historical summaries data and report withdrawal to the module for valid proofs
```solidity
function processHistoricalWithdrawalProof(
ProvableBeaconBlockHeader calldata beaconBlock,
HistoricalHeaderWitness calldata oldBlock,
WithdrawalWitness calldata witness,
uint256 nodeOperatorId,
uint256 keyIndex
) external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`beaconBlock`|`ProvableBeaconBlockHeader`|Beacon block header|
|`oldBlock`|`HistoricalHeaderWitness`|Historical block header witness|
|`witness`|`WithdrawalWitness`|Withdrawal witness|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`keyIndex`|`uint256`|Index of the validator key in the Node Operator's key storage|
### `CSEarlyAdoption.sol`
#### Function: consume
Validate EA eligibility proof and mark it as consumed
*Called only by the module*
```solidity
function consume(address sender, bytes32[] calldata proof) external;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`sender`|`address`|Address to be verified alongside the proof|
|`proof`|`bytes32[]`|Merkle proof of EA eligibility|
#### Function: consumed
Check if the address has already claimed EA access
```solidity
function consumed(address sender) external view returns (bool);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`sender`|`address`|Address to check|
#### Function: isEligible
Check if the address is eligible to claim EA access
```solidity
function isEligible(address sender, bytes32[] calldata proof) public view returns (bool);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`sender`|`address`|Address to check|
|`proof`|`bytes32[]`|Merkle proof of EA eligibility|
### `CSFeeDistributor.sol`
#### Function: distributeFees
Distribute fees to the Accounting in favor of the Node Operator
```solidity
function distributeFees(uint256 nodeOperatorId, uint256 shares, bytes32[] calldata proof)
external
onlyAccounting
returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`shares`|`uint256`|Total Amount of stETH shares earned as fees|
|`proof`|`bytes32[]`|Merkle proof of the leaf|
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`<none>`|`uint256`|Amount of stETH shares distributed|
#### Function: processOracleReport
Receive the data of the Merkle tree from the Oracle contract and process it
```solidity
function processOracleReport(bytes32 _treeRoot, string calldata _treeCid, uint256 distributed)
external
onlyRole(ORACLE_ROLE);
```
#### Function: recoverERC20
Recover ERC20 tokens (except for stETH) from the contract
*Any stETH transferred to feeDistributor is treated as a donation and can not be recovered*
```solidity
function recoverERC20(address token, uint256 amount) external override;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`token`|`address`|Address of the ERC20 token to recover|
|`amount`|`uint256`|Amount of the ERC20 token to recover|
#### Function: pendingToDistribute
Get the Amount of stETH shares that are pending to be distributed
```solidity
function pendingToDistribute() external view returns (uint256);
```
#### Function: getFeesToDistribute
Get the Amount of stETH shares that can be distributed in favor of the Node Operator
```solidity
function getFeesToDistribute(uint256 nodeOperatorId, uint256 shares, bytes32[] calldata proof)
public
view
returns (uint256);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`shares`|`uint256`|Total Amount of stETH shares earned as fees|
|`proof`|`bytes32[]`|Merkle proof of the leaf|
**Returns**
|Name|Type|Description|
|----|----|-----------|
|`<none>`|`uint256`|Amount of stETH shares that can be distributed|
#### Function: hashLeaf
Get a hash of a leaf
*Double hash the leaf to prevent second preimage attacks*
```solidity
function hashLeaf(uint256 nodeOperatorId, uint256 shares) public pure returns (bytes32);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`nodeOperatorId`|`uint256`|ID of the Node Operator|
|`shares`|`uint256`|Amount of stETH shares|
### `CSFeeOracle.sol`
#### Function: setFeeDistributorContract
Set a new fee distributor contract
*_setFeeDistributorContract() reverts if zero address*
```solidity
function setFeeDistributorContract(address feeDistributorContract) external onlyRole(CONTRACT_MANAGER_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`feeDistributorContract`|`address`|Address of the new fee distributor contract|
#### Function: setPerformanceThreshold
Set a new performance threshold value in basis points
```solidity
function setPerformanceThreshold(uint256 valueBP) external onlyRole(CONTRACT_MANAGER_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`valueBP`|`uint256`|performance threshold in basis points|
#### Function: submitReportData
Submit the data for a committee report
```solidity
function submitReportData(ReportData calldata data, uint256 contractVersion) external whenResumed;
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`data`|`ReportData`|Data for a committee report|
|`contractVersion`|`uint256`|Version of the oracle consensus rules|
#### Function: resume
Resume accepting oracle reports
```solidity
function resume() external whenPaused onlyRole(RESUME_ROLE);
```
#### Function: pauseFor
Pause accepting oracle reports for a `duration` seconds
```solidity
function pauseFor(uint256 duration) external onlyRole(PAUSE_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`duration`|`uint256`|Duration of the pause in seconds|
#### Function: pauseUntil
Pause accepting oracle reports until a timestamp
```solidity
function pauseUntil(uint256 pauseUntilInclusive) external onlyRole(PAUSE_ROLE);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
|`pauseUntilInclusive`|`uint256`|Timestamp until which the oracle reports are paused|
#### Function: getConsensusContract
Returns the address of the HashConsensus contract.
```solidity
function getConsensusContract() external view returns (address);
```
#### Function: setConsensusContract
Sets the address of the HashConsensus contract.
```solidity
function setConsensusContract(address addr) external onlyRole(MANAGE_CONSENSUS_CONTRACT_ROLE);
```
#### Function: getConsensusVersion
Returns the current consensus version expected by the oracle contract.
Consensus version must change every time consensus rules change, meaning that
an oracle looking at the same reference slot would calculate a different hash.
```solidity
function getConsensusVersion() external view returns (uint256);
```
#### Function: setConsensusVersion
Sets the consensus version expected by the oracle contract.
```solidity
function setConsensusVersion(uint256 version) external onlyRole(MANAGE_CONSENSUS_VERSION_ROLE);
```
#### Function: getConsensusReport
Data provider interface
Returns the last consensus report hash and metadata.
```solidity
function getConsensusReport()
external
view
returns (bytes32 hash, uint256 refSlot, uint256 processingDeadlineTime, bool processingStarted);
```
#### Function: submitConsensusReport
Consensus contract interface
Called by HashConsensus contract to push a consensus report for processing.
Note that submitting the report doesn't require the processor to start processing it right
away, this can happen later (see `getLastProcessingRefSlot`). Until processing is started,
HashConsensus is free to reach consensus on another report for the same reporting frame an
submit it using this same function, or to lose the consensus on the submitted report,
notifying the processor via `discardConsensusReport`.
```solidity
function submitConsensusReport(bytes32 reportHash, uint256 refSlot, uint256 deadline) external;
```
#### Function: discardConsensusReport
Called by HashConsensus contract to notify that the report for the given ref. slot
is not a conensus report anymore and should be discarded. This can happen when a member
changes their report, is removed from the set, or when the quorum value gets increased.
Only called when, for the given reference slot:
1. there previously was a consensus report; AND
1. processing of the consensus report hasn't started yet; AND
2. report processing deadline is not expired yet; AND
3. there's no consensus report now (otherwise, `submitConsensusReport` is called instead).
Can be called even when there's no submitted non-discarded consensus report for the current
reference slot, i.e. can be called multiple times in succession.
```solidity
function discardConsensusReport(uint256 refSlot) external;
```
#### Function: getLastProcessingRefSlot
Returns the last reference slot for which processing of the report was started.
```solidity
function getLastProcessingRefSlot() external view returns (uint256);
```
## Administrative actions
Community Staking Module contracts support a set of administrative actions, including:
- Changing the configuration options.
- Upgrading the system's code.
Each of these actions can only be performed by a designated admin (`DEFAULT_ADMIN_ROLE`) (set by a configuration option).
## Roles to actors mapping
### `CSModule.sol`
| Role | Assignee |
| ----------------------------------------- | ---------------------- |
| `DEFAULT_ADMIN_ROLE` | Aragon Voting |
| `PAUSE_ROLE` | Gate Seal contract |
| `RESUME_ROLE` | Aragon Voting |
| `MODULE_MANAGER_ROLE` | Aragon Voting |
| `STAKING_ROUTER_ROLE` | StakingRouter contract |
| `REPORT_EL_REWARDS_STEALING_PENALTY_ROLE` | CS Multisig or Bot EOA |
| `SETTLE_EL_REWARDS_STEALING_PENALTY_ROLE` | Dedicated EasyTrack |
| `VERIFIER_ROLE` | `CSVerifier.sol` |
| `RECOVERER_ROLE` | Aragon Voting |
### `CSAccounting.sol`
| Role | Assignee |
| ----------------------------- | ------------------------------ |
| `DEFAULT_ADMIN_ROLE` | Aragon Voting |
| `PAUSE_ROLE` | Gate Seal contract |
| `RESUME_ROLE` | Aragon Voting |
| `ACCOUNTING_MANAGER_ROLE` | Aragon Voting |
| `ADD_BOND_CURVE_ROLE` | Aragon Voting |
| `SET_DEFAULT_BOND_CURVE_ROLE` | Aragon Voting |
| `SET_BOND_CURVE_ROLE` | CS Multisig and `CSModule.sol` |
| `RESET_BOND_CURVE_ROLE` | CS Multisig and `CSModule.sol` |
| `RECOVERER_ROLE` | Aragon Voting |
### `CSFeeDistributor.sol`
| Role | Assignee |
| -------------------- | ----------------- |
| `DEFAULT_ADMIN_ROLE` | Aragon Voting |
| `RECOVERER_ROLE` | Aragon Voting |
| `ORACLE_ROLE` | `CSFeeOracle.sol` |
### `CSFeeOracle.sol`
| Role | Assignee |
| -------------------------------- | ----------------------- |
| `DEFAULT_ADMIN_ROLE` | Aragon Voting |
| `CONTRACT_MANAGER_ROLE` | Aragon Voting |
| `SUBMIT_DATA_ROLE` | Not assigned by default |
| `PAUSE_ROLE` | GateSeal contract |
| `RESUME_ROLE` | Aragon Voting |
| `RECOVERER_ROLE` | Aragon Voting |
| `MANAGE_CONSENSUS_CONTRACT_ROLE` | Aragon Voting |
| `MANAGE_CONSENSUS_VERSION_ROLE` | Aragon Voting |
### `HashConsensus.sol`
| Role | Assignee |
| -------------------------------- | ------------- |
| `DEFAULT_ADMIN_ROLE` | Aragon Voting |
| `MANAGE_MEMBERS_AND_QUORUM_ROLE` | Aragon Voting |
| `DISABLE_CONSENSUS_ROLE` | Aragon Voting |
| `MANAGE_FRAME_CONFIG_ROLE` | Aragon Voting |
| `MANAGE_FAST_LANE_CONFIG_ROLE` | Aragon Voting |
| `MANAGE_REPORT_PROCESSOR_ROLE` | Aragon Voting |
### `CSEarlyAdoption.sol`
Roles are not used for this contract.
### `CSVerifier.sol`
Roles are not used for this contract.
## Upgradability
`CSmodule.sol`, `CSAccounting.sol`, `CSFeeOracle.sol`, and `CSFeeDistributor.sol` are upgradable using [OssifiableProxy](https://github.com/lidofinance/community-staking-module/blob/main/src/lib/proxy/OssifiableProxy.sol) contracts.
`CSVerifier.sol` is not upgradable and should be re-deployed if needed.
## Security considerations
### Bond exposure to negative stETH rebase
The bond stored in stETH inevitably inherits all stETH features, including the possibility of a negative rebase. The effective bond amount (counted in ETH) will decrease in case of a negative rebase. This can lead to the case when a relatively large Node Operator might end up with unbonded keys. Also, it might result in an effective bond being lower than the bond required. Hence, Node Operators will lose part of their rewards.
### Malicious Oracles can steal all unclaimed CSM rewards
A single updatable Merkle tree approach to the rewards distribution allows malicious Oracles to collude and submit a version of the Merkle tree, indicating that all rewards should be allocated to a single Node Operator (previously created by malicious actors). The worst-case scenario is when all unclaimed rewards stored on the CSM contract will be available for claim by a single Node Operator.