CSModule
CSModule.sol is a core module contract conforming to the IStakingModule and IStakingModuleV2 interfaces. The contract stores information about Node Operators and deposit data (DD) and is responsible for all interactions with the StakingRouter, including deposit data queue management. To support 0x02 validators, it also maintains a top-up queue used to fund validators beyond the initial 32 ETH deposit up to 2048 ETH.
A Node Operator can perform a number of operations directly through this contract, for example:
- upload new validator keys (deposit data), supplying the required bond in ETH, stETH, or wstETH;
- remove uploaded keys that have not been deposited yet;
- manage the Node Operator's manager and reward addresses;
- compensate a reported (locked) penalty from the bond.
Upgradability​
The contract uses OssifiableProxy for upgradability.
State Variables​
MANAGE_TOP_UP_QUEUE_ROLE​
bytes32 public constant MANAGE_TOP_UP_QUEUE_ROLE = keccak256("MANAGE_TOP_UP_QUEUE_ROLE")
REWIND_TOP_UP_QUEUE_ROLE​
bytes32 public constant REWIND_TOP_UP_QUEUE_ROLE = keccak256("REWIND_TOP_UP_QUEUE_ROLE")
CSMODULE_STORAGE_LOCATION​
bytes32 private constant CSMODULE_STORAGE_LOCATION =
0x48912ff6aecfe3259bdc07bbe67306543da3ba7172b1471bf49b659c3f4c6d00
INITIALIZED_VERSION​
uint64 internal constant INITIALIZED_VERSION = 3
STAKING_ROUTER_ROLE​
bytes32 public constant STAKING_ROUTER_ROLE = keccak256("STAKING_ROUTER_ROLE")
REPORT_GENERAL_DELAYED_PENALTY_ROLE​
bytes32 public constant REPORT_GENERAL_DELAYED_PENALTY_ROLE = keccak256("REPORT_GENERAL_DELAYED_PENALTY_ROLE")
SETTLE_GENERAL_DELAYED_PENALTY_ROLE​
bytes32 public constant SETTLE_GENERAL_DELAYED_PENALTY_ROLE = keccak256("SETTLE_GENERAL_DELAYED_PENALTY_ROLE")
VERIFIER_ROLE​
bytes32 public constant VERIFIER_ROLE = keccak256("VERIFIER_ROLE")
REPORT_REGULAR_WITHDRAWN_VALIDATORS_ROLE​
bytes32 public constant REPORT_REGULAR_WITHDRAWN_VALIDATORS_ROLE =
keccak256("REPORT_REGULAR_WITHDRAWN_VALIDATORS_ROLE")
REPORT_SLASHED_WITHDRAWN_VALIDATORS_ROLE​
bytes32 public constant REPORT_SLASHED_WITHDRAWN_VALIDATORS_ROLE =
keccak256("REPORT_SLASHED_WITHDRAWN_VALIDATORS_ROLE")
CREATE_NODE_OPERATOR_ROLE​
bytes32 public constant CREATE_NODE_OPERATOR_ROLE = keccak256("CREATE_NODE_OPERATOR_ROLE")
OPERATOR_ADDRESSES_ADMIN_ROLE​
bytes32 public constant OPERATOR_ADDRESSES_ADMIN_ROLE = keccak256("OPERATOR_ADDRESSES_ADMIN_ROLE")
LIDO_LOCATOR​
ILidoLocator public immutable LIDO_LOCATOR
STETH​
IStETH public immutable STETH
PARAMETERS_REGISTRY​
IParametersRegistry public immutable PARAMETERS_REGISTRY
ACCOUNTING​
IAccounting public immutable ACCOUNTING
EXIT_PENALTIES​
IExitPenalties public immutable EXIT_PENALTIES
FEE_DISTRIBUTOR​
address public immutable FEE_DISTRIBUTOR
MODULE_TYPE​
bytes32 internal immutable MODULE_TYPE
Functions​
constructor​
constructor(
bytes32 moduleType,
address lidoLocator,
address parametersRegistry,
address accounting,
address exitPenalties
) BaseModule(moduleType, lidoLocator, parametersRegistry, accounting, exitPenalties);
initialize​
Initialize contract from scratch. In case of a method call frontrun, the contract instance should be discarded. It is recommended to call this method in the same transaction as the deployment transaction and perform extensive deployment verification before using the contract instance.
function initialize(address admin, uint8 topUpQueueLimit) external reinitializer(INITIALIZED_VERSION);
finalizeUpgradeV3​
This method is expected to be called only when the contract is upgraded from version 2 to version 3 for the existing version 2 deployment.
If the version 3 contract is deployed from scratch, the initialize method should be used instead.
To prevent possible frontrun this method should strictly be called in the same TX as the upgrade transaction and should not be called separately.
function finalizeUpgradeV3() external reinitializer(INITIALIZED_VERSION);
rebuildTotalWithdrawnValidators​
Rebuilds the global withdrawn validator counter from per-operator counters.
One-time migration helper for v2-to-v3 upgrades. The function is permissionless because the resulting value is fully derived from stored Node Operator state.
function rebuildTotalWithdrawnValidators() external;
createNodeOperator​
Permissioned method to add a new Node Operator
Should be called by *Gate.sol contracts. See PermissionlessGate.sol and VettedGate.sol for examples
function createNodeOperator(
address from,
NodeOperatorManagementProperties calldata managementProperties,
address referrer
) public override(BaseModule, IBaseModule) returns (uint256 nodeOperatorId);
Parameters
| Name | Type | Description |
|---|---|---|
from | address | Sender address. Initial sender address to be used as a default manager and reward addresses. Gates must pass the correct address in order to specify which address should be the owner of the Node Operator. |
managementProperties | NodeOperatorManagementProperties | Optional. Management properties to be used for the Node Operator. managerAddress: Used as managerAddress for the Node Operator. If not passed from will be used. rewardAddress: Used as rewardAddress for the Node Operator. If not passed from will be used. extendedManagerPermissions: Flag indicating that managerAddress will be able to change rewardAddress. If set to true resetNodeOperatorManagerAddress method will be disabled |
referrer | address | Optional. Referrer address. Should be passed when Node Operator is created using partners integration |
obtainDepositData​
Get the next depositsCount of depositable keys with signatures from the queue
The method does not update depositable keys count for the Node Operators before the queue processing start. Hence, in the rare cases of negative stETH rebase the method might return unbonded keys. This is a trade-off between the gas cost and the correctness of the data. Due to module design, any unbonded keys will be requested to exit by VEBO.
Second param depositCalldata is not used
function obtainDepositData(
uint256 depositsCount,
bytes calldata depositCalldata // solhint-disable-line no-unused-vars
)
external
returns (bytes memory publicKeys, bytes memory signatures);
Parameters
| Name | Type | Description |
|---|---|---|
depositsCount | uint256 | Number of deposits to be done |
depositCalldata | bytes | Staking module defined data encoded as bytes. IMPORTANT: depositCalldata MUST NOT modify the deposit data set of the staking module |
Returns
| Name | Type | Description |
|---|---|---|
publicKeys | bytes | Batch of the concatenated public validators keys |
signatures | bytes | Batch of the concatenated deposit signatures for returned public keys |
allocateDeposits​
Validates that provided keys belong to the corresponding operators in the module and calculates deposit allocations for top-up
The function strictly follows the top-up queue. If the provided deposit amount can be distributed only on 4 keys, but 5 keys were provided, then the function reverts.
function allocateDeposits(
uint256 maxDepositAmount,
bytes[] calldata pubkeys,
uint256[] calldata keyIndices,
uint256[] calldata operatorIds,
uint256[] calldata topUpLimits
) external returns (uint256[] memory allocations);
Parameters
| Name | Type | Description |
|---|---|---|
maxDepositAmount | uint256 | Total ether amount available for top-up (must be multiple of 1 gwei) |
pubkeys | bytes[] | List of validator public keys to top up |
keyIndices | uint256[] | Indices of keys within their respective operators |
operatorIds | uint256[] | Node operator IDs that own the keys |
topUpLimits | uint256[] | Maximum amount that can be deposited per key based on CL data and SR internal logic. |
Returns
| Name | Type | Description |
|---|---|---|
allocations | uint256[] | Amount to deposit to each key |
reportValidatorBalance​
Update verified on-chain balance for a key.
The function stores balance relative to MIN_ACTIVATION_BALANCE.
function reportValidatorBalance(uint256 nodeOperatorId, uint256 keyIndex, uint256 currentBalanceWei)
public
override(BaseModule, IBaseModule);
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
keyIndex | uint256 | Index of the key in the Node Operator's keys storage |
currentBalanceWei | uint256 | Proven current validator balance in wei |
setTopUpQueueLimit​
Set the top-up queue capacity limit.
function setTopUpQueueLimit(uint256 limit) external;
Parameters
| Name | Type | Description |
|---|---|---|
limit | uint256 | How many items may sit in the top-up queue at most. |
removeKeys​
Remove keys for the Node Operator. Charging is module-specific (e.g., CSM applies a per-key fee).
This method is a part of the Optimistic Vetting scheme. After key deletion totalVettedKeys
is set equal to totalAddedKeys. If invalid keys are not removed, the unvetting process will be repeated
and decreaseVettedSigningKeysCount will be called by StakingRouter.
function removeKeys(uint256 nodeOperatorId, uint256 startIndex, uint256 keysCount)
external
override(BaseModule, IBaseModule);
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
startIndex | uint256 | Index of the first key |
keysCount | uint256 | Keys count to delete |
rewindTopUpQueue​
Rewind the top-up queue to be able to deposit to mistakenly skipped items.
function rewindTopUpQueue(uint256 to) external;
Parameters
| Name | Type | Description |
|---|---|---|
to | uint256 | Pointer to move the queue head to. |
cleanDepositQueue​
Clean the deposit queue from batches with no depositable keys
Use eth_call to check how many items will be removed
function cleanDepositQueue(uint256 maxItems) external returns (uint256 removed, uint256 lastRemovedAtDepth);
Parameters
| Name | Type | Description |
|---|---|---|
maxItems | uint256 | How many queue items to review |
Returns
| Name | Type | Description |
|---|---|---|
removed | uint256 | Count of batches to be removed by visiting maxItems batches |
lastRemovedAtDepth | uint256 | The value to use as maxItems to remove removed batches if the static call of the method was used |
getTopUpQueue​
Returns the top-up queue stats.
function getTopUpQueue() external view returns (bool enabled, uint256 limit, uint256 length, uint256 head);
Returns
| Name | Type | Description |
|---|---|---|
enabled | bool | Whether the queue was enabled upon initialization of the module. |
limit | uint256 | How many items may sit in the top-up queue at most. |
length | uint256 | How many items are in the queue. |
head | uint256 | Pointer to the head of the queue. |
getTopUpQueueItem​
Returns the top-up queue item by the given index.
function getTopUpQueueItem(uint256 index) external view returns (uint256 nodeOperatorId, uint256 keyIndex);
Parameters
| Name | Type | Description |
|---|---|---|
index | uint256 | An offset from the current head (not a global index) of the item to retrieve. |
Returns
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | Node operator ID. |
keyIndex | uint256 | Index of the key in the Node Operator's keys storage |
getStakingModuleSummary​
Returns all-validators summary in the staking module
function getStakingModuleSummary()
external
view
override(BaseModule, IStakingModule)
returns (uint256 totalExitedValidators, uint256 totalDepositedValidators, uint256 depositableValidatorsCount);
Returns
| Name | Type | Description |
|---|---|---|
totalExitedValidators | uint256 | Total number of validators in the EXITED state on the Consensus Layer. This value can't decrease in normal conditions |
totalDepositedValidators | uint256 | Total number of validators deposited via the official Deposit Contract. This value is a cumulative counter: even when the validator goes into EXITED state this counter is not decreasing |
depositableValidatorsCount | uint256 | Number of validators in the set available for deposit |
depositQueuePointers​
Get the pointers to the head and tail of queue with the given priority.
function depositQueuePointers(uint256 queuePriority) external view returns (uint128 head, uint128 tail);
Parameters
| Name | Type | Description |
|---|---|---|
queuePriority | uint256 | Priority of the queue to get the pointers. |
Returns
| Name | Type | Description |
|---|---|---|
head | uint128 | Pointer to the head of the queue. |
tail | uint128 | Pointer to the tail of the queue. |
depositQueueItem​
Get the deposit queue item by an index
function depositQueueItem(uint256 queuePriority, uint128 index) external view returns (Batch);
Parameters
| Name | Type | Description |
|---|---|---|
queuePriority | uint256 | Priority of the queue to get an item from |
index | uint128 | Index of a queue item |
Returns
| Name | Type | Description |
|---|---|---|
<none> | Batch | Deposit queue item from the priority queue |
getKeysForTopUp​
Fetches up to maxKeyCount validator public keys from the top-up queue.
If the queue contains fewer than maxKeyCount entries, all available keys are returned.
function getKeysForTopUp(uint256 maxKeyCount) external view returns (bytes[] memory pubkeys);
Parameters
| Name | Type | Description |
|---|---|---|
maxKeyCount | uint256 | The maximum number of keys to retrieve. |
Returns
| Name | Type | Description |
|---|---|---|
pubkeys | bytes[] | The list of validator public keys returned from the queue. |
addValidatorKeysETH​
Add new keys to the existing Node Operator using ETH as a bond
Any excess msg.value will be sent to the bond and can be claimed from there. This behaviour is intentional and protects users from key upload transaction front runs rendering the user transaction invalid due to changes in the required bond amount.
function addValidatorKeysETH(
address from,
uint256 nodeOperatorId,
uint256 keysCount,
bytes calldata publicKeys,
bytes calldata signatures
) external payable whenResumed;
Parameters
| Name | Type | Description |
|---|---|---|
from | address | Sender address. Commonly equals to msg.sender except for the case of Node Operator creation by *Gate.sol contracts |
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 |
addValidatorKeysStETH​
Add new keys to the existing Node Operator using stETH as a bond
function addValidatorKeysStETH(
address from,
uint256 nodeOperatorId,
uint256 keysCount,
bytes calldata publicKeys,
bytes calldata signatures,
IAccounting.PermitInput calldata permit
) external whenResumed;
Parameters
| Name | Type | Description |
|---|---|---|
from | address | Sender address. Commonly equals to msg.sender except for the case of Node Operator creation by *Gate.sol contracts |
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 | IAccounting.PermitInput | Optional. Permit to use stETH as bond |
addValidatorKeysWstETH​
Add new keys to the existing Node Operator using wstETH as a bond
function addValidatorKeysWstETH(
address from,
uint256 nodeOperatorId,
uint256 keysCount,
bytes calldata publicKeys,
bytes calldata signatures,
IAccounting.PermitInput calldata permit
) external whenResumed;
Parameters
| Name | Type | Description |
|---|---|---|
from | address | Sender address. Commonly equals to msg.sender except for the case of Node Operator creation by *Gate.sol contracts |
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 | IAccounting.PermitInput | Optional. Permit to use wstETH as bond |
proposeNodeOperatorManagerAddressChange​
Propose a new manager address for the Node Operator.
Passing address(0) clears the pending proposal without changing the current manager address.
function proposeNodeOperatorManagerAddressChange(uint256 nodeOperatorId, address proposedAddress) external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
proposedAddress | address | Proposed manager address, or address(0) to cancel the current proposal |
confirmNodeOperatorManagerAddressChange​
Confirm a new manager address for the Node Operator. Should be called from the currently proposed address
function confirmNodeOperatorManagerAddressChange(uint256 nodeOperatorId) external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
proposeNodeOperatorRewardAddressChange​
Propose a new reward address for the Node Operator.
Passing address(0) clears the pending proposal without changing the current reward address.
function proposeNodeOperatorRewardAddressChange(uint256 nodeOperatorId, address proposedAddress) external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
proposedAddress | address | Proposed reward address, or address(0) to cancel the current proposal |
confirmNodeOperatorRewardAddressChange​
Confirm a new reward address for the Node Operator. Should be called from the currently proposed address
function confirmNodeOperatorRewardAddressChange(uint256 nodeOperatorId) external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
resetNodeOperatorManagerAddress​
Reset the manager address to the reward address. Should be called from the reward address
function resetNodeOperatorManagerAddress(uint256 nodeOperatorId) external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
changeNodeOperatorRewardAddress​
Change rewardAddress if extendedManagerPermissions is enabled for the Node Operator
function changeNodeOperatorRewardAddress(uint256 nodeOperatorId, address newAddress) external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
newAddress | address | Proposed reward address |
changeNodeOperatorAddresses​
Change both reward and manager addresses of a node operator. An emergency method.
Only privileged role member can call this method if the role is assigned.
function changeNodeOperatorAddresses(uint256 nodeOperatorId, address newManagerAddress, address newRewardAddress)
external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
newManagerAddress | address | New manager address |
newRewardAddress | address | New reward address |
onRewardsMinted​
Called by StakingRouter to signal that stETH rewards were minted for this module.
Passes through the minted stETH shares to the fee distributor
function onRewardsMinted(uint256 totalShares) external;
Parameters
| Name | Type | Description |
|---|---|---|
totalShares | uint256 | Amount of stETH shares that were minted to reward all node operators. |
updateExitedValidatorsCount​
Updates the number of the validators in the EXITED state for node operator with given id
exitedValidatorsCount is not used inside the module, but SR still expects this data to be stored and returned. The method should be removed once there are no legacy modules in the Lido protocol and SR no longer calls this method.
function updateExitedValidatorsCount(bytes calldata nodeOperatorIds, bytes calldata exitedValidatorsCounts)
external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorIds | bytes | Packed array of the node operators id |
exitedValidatorsCounts | bytes | Packed array of the new number of EXITED validators for the node operators |
unsafeUpdateValidatorsCount​
Unsafely updates the number of validators in the EXITED/STUCK states for node operator with given id 'unsafely' means that this method can both increase and decrease exited and stuck counters
exitedValidatorsCount is not used inside the module, but SR still expects this data to be stored and returned. The method should be removed once there are no legacy modules in the Lido protocol and SR no longer calls this method.
function unsafeUpdateValidatorsCount(uint256 nodeOperatorId, uint256 exitedValidatorsCount) external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | |
exitedValidatorsCount | uint256 |
updateTargetValidatorsLimits​
Updates the limit of the validators that can be used for deposit
function updateTargetValidatorsLimits(uint256 nodeOperatorId, uint256 targetLimitMode, uint256 targetLimit)
external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
targetLimitMode | uint256 | Target limit mode for the Node Operator (see https://hackmd.io/@lido/BJXRTxMRp) 0 - disabled 1 - soft mode 2 - forced mode |
targetLimit | uint256 | Target limit of validators |
decreaseVettedSigningKeysCount​
Called by StakingRouter to decrease the number of vetted keys for Node Operators with given ids
function decreaseVettedSigningKeysCount(bytes calldata nodeOperatorIds, bytes calldata vettedSigningKeysCounts)
external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorIds | bytes | Bytes packed array of the Node Operator ids |
vettedSigningKeysCounts | bytes | Bytes packed array of the new numbers of vetted keys for the Node Operators |
updateDepositableValidatorsCount​
Update depositable validators data for the given Node Operator.
The following rules are applied:
- Unbonded keys can not be depositable
- Unvetted keys can not be depositable
- Depositable keys count should respect targetLimit value
function updateDepositableValidatorsCount(uint256 nodeOperatorId) external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
reportGeneralDelayedPenalty​
Report general delayed penalty for the given Node Operator
function reportGeneralDelayedPenalty(
uint256 nodeOperatorId,
bytes32 penaltyType,
uint256 amount,
string calldata details
) external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
penaltyType | bytes32 | Type of the penalty |
amount | uint256 | Penalty amount in ETH |
details | string | Additional details about the penalty |
cancelGeneralDelayedPenalty​
Cancel previously reported and not settled general delayed penalty for the given Node Operator
function cancelGeneralDelayedPenalty(uint256 nodeOperatorId, uint256 amount) external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
amount | uint256 | Amount of penalty to cancel |
settleGeneralDelayedPenalty​
Settles locked bond for eligible Node Operators
SETTLE_GENERAL_DELAYED_PENALTY_ROLE role is expected to be assigned to Easy Track
function settleGeneralDelayedPenalty(uint256[] calldata nodeOperatorIds, uint256[] calldata bondLockNonces)
external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorIds | uint256[] | IDs of the Node Operators |
bondLockNonces | uint256[] | Bond lock nonces for each Node Operator |
compensateGeneralDelayedPenalty​
Compensate general delayed penalty (locked bond) for the given Node Operator from Node Operator's bond
Can only be called by the Node Operator manager
function compensateGeneralDelayedPenalty(uint256 nodeOperatorId) external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
reportValidatorSlashing​
Report Node Operator's key as slashed.
function reportValidatorSlashing(uint256 nodeOperatorId, uint256 keyIndex) external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | The ID of the Node Operator |
keyIndex | uint256 | Index of the key in the Node Operator's keys storage |
reportSlashedWithdrawnValidators​
Report withdrawn validators that have been slashed.
function reportSlashedWithdrawnValidators(WithdrawnValidatorInfo[] calldata validatorInfos) external;
Parameters
| Name | Type | Description |
|---|---|---|
validatorInfos | WithdrawnValidatorInfo[] | An array of WithdrawnValidatorInfo structs |
reportRegularWithdrawnValidators​
Report Node Operator's keys as withdrawn and charge penalties associated with exit if any. A validator is considered withdrawn in the following cases:
- if it's an exit of a non-slashed validator, when a withdrawal of the validator is included in a beacon block;
- if it's an exit of a slashed validator, when the committee reports such a validator as withdrawn; note that it can happen earlier than the actual withdrawal is included on the beacon chain if the committee decides it can account for all penalties in advance;
- if it's a consolidated validator, when the corresponding pending consolidation is processed and the balance of the validator has been moved to another validator.
function reportRegularWithdrawnValidators(WithdrawnValidatorInfo[] calldata validatorInfos) external;
Parameters
| Name | Type | Description |
|---|---|---|
validatorInfos | WithdrawnValidatorInfo[] | An array of WithdrawnValidatorInfo structs |
reportValidatorExitDelay​
Handles tracking and penalization logic for a validator that remains active beyond its eligible exit window.
This function is called by the StakingRouter to report the current exit-related status of a validator belonging to a specific node operator. It accepts a validator's public key, associated with the duration (in seconds) it was eligible to exit but has not exited. This data could be used to trigger penalties for the node operator if the validator has exceeded the allowed exit window.
function reportValidatorExitDelay(
uint256 nodeOperatorId,
uint256 proofSlotTimestamp, // solhint-disable-line no-unused-vars
bytes calldata publicKey,
uint256 eligibleToExitInSec
) external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | |
proofSlotTimestamp | uint256 | |
publicKey | bytes | |
eligibleToExitInSec | uint256 |
onValidatorExitTriggered​
Handles the triggerable exit event for a validator belonging to a specific node operator.
This function is called by the StakingRouter when a validator is exited using the triggerable exit request on the Execution Layer (EL).
function onValidatorExitTriggered(
uint256 nodeOperatorId,
bytes calldata publicKey,
uint256 elWithdrawalRequestFeePaid,
uint256 exitType
) external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | |
publicKey | bytes | |
elWithdrawalRequestFeePaid | uint256 | |
exitType | uint256 |
updateDepositInfo​
Update deposit info for the given Node Operator.
function updateDepositInfo(uint256 nodeOperatorId) external;
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
requestFullDepositInfoUpdate​
Request a full update of deposit info for all node operators. Should be called after external changes that can affect deposit info such as bond curve change or parameters update.
function requestFullDepositInfoUpdate() external;
batchDepositInfoUpdate​
Request a batch update of deposit info for node operators.
If requestFullDepositInfoUpdate was called before, the update will start from the first operator.
Otherwise, it will continue from the next operator after the last updated one.
function batchDepositInfoUpdate(uint256 maxCount) external returns (uint256 operatorsLeft);
Parameters
| Name | Type | Description |
|---|---|---|
maxCount | uint256 | Maximum number of operators to update in this batch |
Returns
| Name | Type | Description |
|---|---|---|
operatorsLeft | uint256 | Number of operators left to update |
onExitedAndStuckValidatorsCountsUpdated​
Called by StakingRouter after it finishes updating exited and stuck validators counts for this module's node operators. Guaranteed to be called after an oracle report is applied, regardless of whether any node operator in this module has actually received any updated counts as a result of the report but given that the total number of exited validators returned from getStakingModuleSummary is the same as StakingRouter expects based on the total count received from the oracle.
This method is not used in the module since rewards are distributed by a performance oracle, hence it does nothing
function onExitedAndStuckValidatorsCountsUpdated() external view;
onWithdrawalCredentialsChanged​
Called by StakingRouter when withdrawal credentials are changed.
Changing the WC means that the current deposit data in the queue is not valid anymore and can't be deposited. If there are depositable validators in the queue, the method should revert to prevent deposits with invalid withdrawal credentials.
function onWithdrawalCredentialsChanged() external view;
getInitializedVersion​
Returns the initialized version of the contract
function getInitializedVersion() external view returns (uint64);
isValidatorSlashed​
Checks if a validator was reported as slashed
function isValidatorSlashed(uint256 nodeOperatorId, uint256 keyIndex) external view returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | The ID of the node operator |
keyIndex | uint256 | Index of the key in the Node Operator's keys storage |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | True if a validator was reported as slashed |
isValidatorWithdrawn​
Check if the given Node Operator's key is reported as withdrawn
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 in the Node Operator's keys storage |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | Is validator reported as withdrawn or not |
getType​
Returns the type of the staking module
function getType() external view returns (bytes32);
Returns
| Name | Type | Description |
|---|---|---|
<none> | bytes32 | Module type |
getNodeOperator​
Get Node Operator info
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 |
getNodeOperatorManagementProperties​
Get Node Operator management properties
function getNodeOperatorManagementProperties(uint256 nodeOperatorId)
external
view
returns (NodeOperatorManagementProperties memory);
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
Returns
| Name | Type | Description |
|---|---|---|
<none> | NodeOperatorManagementProperties | Node Operator management properties |
getNodeOperatorOwner​
Get Node Operator owner. Owner is manager address if extendedManagerPermissions is enabled and reward address otherwise
function getNodeOperatorOwner(uint256 nodeOperatorId) external view returns (address);
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
Returns
| Name | Type | Description |
|---|---|---|
<none> | address | Node Operator owner |
getNodeOperatorNonWithdrawnKeys​
Get Node Operator non-withdrawn keys
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 |
getNodeOperatorBalance​
Returns tracked operator balance (active validator base stake plus tracked extra).
The tracked extra is intentionally monotonic for active validators and is reduced on withdrawal reporting, not on intermediate balance decreases, so the value serves both top-up allocation and withdrawal penalty accounting.
function getNodeOperatorBalance(uint256 nodeOperatorId) external view returns (uint256);
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | ID of the Node Operator |
getNodeOperatorSummary​
depositableValidatorsCount depends on:
- totalVettedKeys
- totalDepositedKeys
- totalExitedKeys
- targetLimitMode
- targetValidatorsCount
- totalUnbondedKeys
function getNodeOperatorSummary(uint256 nodeOperatorId)
external
view
returns (
uint256 targetLimitMode,
uint256 targetValidatorsCount,
uint256 stuckValidatorsCount,
uint256 refundedValidatorsCount,
uint256 stuckPenaltyEndTimestamp,
uint256 totalExitedValidators,
uint256 totalDepositedValidators,
uint256 depositableValidatorsCount
);
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | id of the operator to return report for |
Returns
| Name | Type | Description |
|---|---|---|
targetLimitMode | uint256 | shows whether the current target limit applied to the node operator (1 = soft mode, 2 = forced mode) |
targetValidatorsCount | uint256 | relative target active validators limit for operator |
stuckValidatorsCount | uint256 | number of validators with an expired request to exit time |
refundedValidatorsCount | uint256 | number of validators that can't be withdrawn, but deposit costs were compensated to the Lido by the node operator |
stuckPenaltyEndTimestamp | uint256 | time when the penalty for stuck validators stops applying to node operator rewards |
totalExitedValidators | uint256 | total number of validators in the EXITED state on the Consensus Layer. This value can't decrease in normal conditions |
totalDepositedValidators | uint256 | total number of validators deposited via the official Deposit Contract. This value is a cumulative counter: even when the validator goes into EXITED state this counter is not decreasing |
depositableValidatorsCount | uint256 | number of validators in the set available for deposit |
getSigningKeys​
Get Node Operator signing keys
function getSigningKeys(uint256 nodeOperatorId, uint256 startIndex, uint256 keysCount)
external
view
returns (bytes memory keys);
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 |
getSigningKeysWithSignatures​
Get Node Operator signing keys with signatures
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 |
getNonce​
Returns a counter that MUST change its value whenever the deposit data set changes. Below is the typical list of actions that requires an update of the nonce:
- a node operator's deposit data is added
- a node operator's deposit data is removed
- a node operator's ready-to-deposit data size is changed
- a node operator was activated/deactivated
- a node operator's deposit data is used for the deposit Note: Depending on the StakingModule implementation above list might be extended
In some scenarios, it's allowed to update nonce without actual change of the deposit data subset, but it MUST NOT lead to the DOS of the staking module via continuous update of the nonce by the malicious actor
function getNonce() external view returns (uint256);
getNodeOperatorsCount​
Returns total number of node operators
function getNodeOperatorsCount() external view returns (uint256);
getActiveNodeOperatorsCount​
Returns number of active node operators
The module has no inactive Node Operator state, so active operators are all existing operators.
function getActiveNodeOperatorsCount() external view returns (uint256);
getNodeOperatorIsActive​
Returns if the node operator with given id is active
The module has no inactive Node Operator state, so active means existing.
function getNodeOperatorIsActive(uint256 nodeOperatorId) external view returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | Id of the node operator |
getNodeOperatorIds​
Returns up to limit node operator ids starting from the offset. The order of
the returned ids is not defined and might change between calls.
This view must not revert in case of invalid data passed. When offset exceeds the
total node operators count or when limit is equal to 0 MUST be returned empty array.
function getNodeOperatorIds(uint256 offset, uint256 limit)
external
view
returns (uint256[] memory nodeOperatorIds);
isValidatorExitDelayPenaltyApplicable​
Determines whether a validator's exit status should be updated and will have an effect on the Node Operator.
function isValidatorExitDelayPenaltyApplicable(
uint256 nodeOperatorId,
uint256 proofSlotTimestamp, // solhint-disable-line no-unused-vars
bytes calldata publicKey,
uint256 eligibleToExitInSec
) external view returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 | |
proofSlotTimestamp | uint256 | |
publicKey | bytes | |
eligibleToExitInSec | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | Returns true if the contract should receive the updated status of the validator. |
exitDeadlineThreshold​
Returns the number of seconds after which a validator is considered late.
function exitDeadlineThreshold(uint256 nodeOperatorId) external view returns (uint256);
Parameters
| Name | Type | Description |
|---|---|---|
nodeOperatorId | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | The exit deadline threshold in seconds. |
getKeyAllocatedBalances​
Get cumulative top-up amounts allocated to Node Operator keys (above MIN_ACTIVATION_BALANCE)
function getKeyAllocatedBalances(uint256 nodeOperatorId, uint256 startIndex, uint256 keysCount)
external
view
returns (uint256[] memory balances);
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 |
|---|---|---|
balances | uint256[] | Allocated balances above MIN_ACTIVATION_BALANCE (wei) |
getKeyConfirmedBalances​
Get verifier-confirmed balances for Node Operator keys (above MIN_ACTIVATION_BALANCE)
function getKeyConfirmedBalances(uint256 nodeOperatorId, uint256 startIndex, uint256 keysCount)
external
view
returns (uint256[] memory balances);
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 |
|---|---|---|
balances | uint256[] | Confirmed balances above MIN_ACTIVATION_BALANCE (wei) |
getTotalModuleStake​
Returns the total tracked stake of the module in wei.
This is the sum of the activation base for active validators and tracked extra stake. The tracked extra is intentionally reduced on withdrawal reporting rather than on intermediate validator balance decreases.
function getTotalModuleStake() public view override returns (uint256);
getNodeOperatorDepositInfoToUpdateCount​
Get the number of Node Operators with outdated deposit info that requires update.
function getNodeOperatorDepositInfoToUpdateCount() external view returns (uint256 count);
_applyDepositableValidatorsCount​
function _applyDepositableValidatorsCount(
NodeOperator storage no,
uint256 nodeOperatorId,
uint256 newCount,
bool incrementNonceIfUpdated
) internal override returns (bool changed);
_addKeysAndUpdateDepositableValidatorsCount​
function _addKeysAndUpdateDepositableValidatorsCount(
uint256 nodeOperatorId,
uint256 keysCount,
bytes calldata publicKeys,
bytes calldata signatures
) internal override;
_initTopUpQueue​
Setting topUpQueueLimit to 0 effectively disables the top-up queue permanently.
function _initTopUpQueue(uint8 topUpQueueLimit) internal;
_onlyEnabledTopUpQueue​
function _onlyEnabledTopUpQueue() internal view;
_topUpQueue​
function _topUpQueue() internal view returns (TopUpQueueLib.Queue storage);
_topUpQueueEnabled​
function _topUpQueueEnabled() internal view returns (bool enabled);
_queueLowestPriority​
function _queueLowestPriority() internal view returns (uint256);
_checkCanAddKeys​
function _checkCanAddKeys(uint256 nodeOperatorId, address who) internal view override;
_csmStorage​
function _csmStorage() internal pure returns (CSModuleStorage storage $);
__BaseModule_init​
function __BaseModule_init(address admin) internal onlyInitializing;
_updateDepositInfo​
function _updateDepositInfo(uint256 nodeOperatorId) internal virtual;
_reportWithdrawnValidators​
function _reportWithdrawnValidators(WithdrawnValidatorInfo[] calldata validatorInfos, bool slashed) internal;
_incrementModuleNonce​
function _incrementModuleNonce() internal;
_updateDepositableValidatorsCount​
function _updateDepositableValidatorsCount(uint256 nodeOperatorId, bool incrementNonceIfUpdated)
internal
returns (bool changed);
_removeKeys​
function _removeKeys(uint256 nodeOperatorId, uint256 startIndex, uint256 keysCount, bool useKeyRemovalCharge)
internal
virtual;
_onlyNodeOperatorManager​
function _onlyNodeOperatorManager(uint256 nodeOperatorId, address from) internal view;
_nodeOperatorExists​
function _nodeOperatorExists(uint256 nodeOperatorId) internal view returns (bool);
_onlyExistingNodeOperator​
function _onlyExistingNodeOperator(uint256 nodeOperatorId) internal view;
_onlyValidIndexRange​
NOTE: The function does not revert when startIndex is equal to totalAddedKeys and keysCount is zero. The
method might be fixed later once we're sure all off-chain tooling will handle the updated behaviour.
function _onlyValidIndexRange(uint256 nodeOperatorId, uint256 startIndex, uint256 keysCount) internal view;
_onlyValidKeyIndex​
function _onlyValidKeyIndex(uint256 nodeOperatorId, uint256 keyIndex) internal view;
_getBondCurveId​
function _getBondCurveId(uint256 nodeOperatorId) internal view returns (uint256);
_getRequiredBondForNextKeys​
function _getRequiredBondForNextKeys(IAccounting accounting, uint256 nodeOperatorId, uint256 keysCount)
internal
view
returns (uint256 amount);
_checkStakingRouterRole​
function _checkStakingRouterRole() internal view;
_checkReportGeneralDelayedPenaltyRole​
function _checkReportGeneralDelayedPenaltyRole() internal view;
_checkVerifierRole​
function _checkVerifierRole() internal view;
_checkCreateNodeOperatorRole​
function _checkCreateNodeOperatorRole() internal view;
_accounting​
This function is used to get the accounting contract from immutables to save bytecode.
function _accounting() internal view returns (IAccounting);
_exitPenalties​
This function is used to get the exit penalties contract from immutables to save bytecode.
function _exitPenalties() internal view returns (IExitPenalties);
_parametersRegistry​
This function is used to get the parameters registry contract from immutables to save bytecode.
function _parametersRegistry() internal view returns (IParametersRegistry);
_requireDepositInfoUpToDate​
function _requireDepositInfoUpToDate() internal view;
_canRequestDepositInfoUpdate​
Default implementation of the guard for requesting deposit info update.
function _canRequestDepositInfoUpdate() internal view virtual;
_onlyRecoverer​
function _onlyRecoverer() internal view override;
__checkRole​
function __checkRole(bytes32 role) internal view override;
Structs​
CSModuleStorage​
Note: storage-location: erc7201:CSModule
struct CSModuleStorage {
TopUpQueueLib.Queue topUpQueue;
}