Skip to main content

CSFeeDistributor

CSFeeDistributor.sol is a supplementary contract that stores non-claimed and non-distributed Node Operator rewards on its balance. This contract stores the latest root of a rewards distribution Merkle tree. It accepts calls from 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 module's rewards. This contract transfers excess rewards allocated by StakingRouter due to variable Node Operator reward share back to Lido treasury.

Changes in v2:

  • Added storage of the distribution history;
  • Added support of the variable Node Operator reward share and rebate transfer to Lido treasury;

Upgradability​

The contract uses OssifiableProxy for upgradability.

State Variables​

RECOVERER_ROLE​

bytes32 public constant RECOVERER_ROLE = keccak256("RECOVERER_ROLE");

STETH​

IStETH public immutable STETH;

ACCOUNTING​

address public immutable ACCOUNTING;

ORACLE​

address public immutable ORACLE;

treeRoot​

The latest Merkle Tree root

bytes32 public treeRoot;

treeCid​

CID of the last published Merkle tree

string public treeCid;

logCid​

CID of the file with log for the last frame reported

string public logCid;

distributedShares​

Amount of stETH shares sent to the Accounting in favor of the NO

mapping(uint256 nodeOperatorId => uint256 distributed) public distributedShares;

totalClaimableShares​

Total Amount of stETH shares available for claiming by NOs

uint256 public totalClaimableShares;

distributionDataHistoryCount​

The number of _distributionDataHistory records

uint256 public distributionDataHistoryCount;

rebateRecipient​

The address to transfer rebate to

address public rebateRecipient;

Functions​

setRebateRecipient​

Set address to send rebate to

function setRebateRecipient(address _rebateRecipient) external onlyRole(DEFAULT_ADMIN_ROLE);

Parameters

NameTypeDescription
_rebateRecipientaddressAddress to send rebate to

distributeFees​

Distribute fees to the Accounting in favor of the Node Operator

function distributeFees(uint256 nodeOperatorId, uint256 cumulativeFeeShares, bytes32[] calldata proof)
external
onlyAccounting
returns (uint256 sharesToDistribute);

Parameters

NameTypeDescription
nodeOperatorIduint256ID of the Node Operator
cumulativeFeeSharesuint256Total Amount of stETH shares earned as fees
proofbytes32[]Merkle proof of the leaf

Returns

NameTypeDescription
sharesToDistributeuint256Amount of stETH shares distributed

processOracleReport​

Receive the data of the Merkle tree from the Oracle contract and process it

function processOracleReport(
bytes32 _treeRoot,
string calldata _treeCid,
string calldata _logCid,
uint256 distributed,
uint256 rebate,
uint256 refSlot
) external onlyOracle;

Parameters

NameTypeDescription
_treeRootbytes32Root of the Merkle tree
_treeCidstringan IPFS CID of the tree
_logCidstringan IPFS CID of the log
distributeduint256an amount of the distributed shares
rebateuint256an amount of the rebate shares
refSlotuint256refSlot of the report

recoverERC20​

Allows sender to recover ERC20 tokens held by the contract

function recoverERC20(address token, uint256 amount) external override;

Parameters

NameTypeDescription
tokenaddressThe address of the ERC20 token to recover
amountuint256The amount of the ERC20 token to recover Emits an ERC20Recovered event upon success Optionally, the inheriting contract can override this function to add additional restrictions

getInitializedVersion​

Get the initialized version of the contract

function getInitializedVersion() external view returns (uint64);

pendingSharesToDistribute​

Get the Amount of stETH shares that are pending to be distributed

function pendingSharesToDistribute() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256pendingShares Amount shares that are pending to distribute

getHistoricalDistributionData​

Get the historical record of distribution data

function getHistoricalDistributionData(uint256 index) external view returns (DistributionData memory);

Parameters

NameTypeDescription
indexuint256Historical entry index

Returns

NameTypeDescription
<none>DistributionDataHistorical distribution data

getFeesToDistribute​

Get the Amount of stETH shares that can be distributed in favor of the Node Operator

function getFeesToDistribute(uint256 nodeOperatorId, uint256 cumulativeFeeShares, bytes32[] calldata proof)
public
view
returns (uint256 sharesToDistribute);

Parameters

NameTypeDescription
nodeOperatorIduint256ID of the Node Operator
cumulativeFeeSharesuint256Total Amount of stETH shares earned as fees
proofbytes32[]Merkle proof of the leaf

Returns

NameTypeDescription
sharesToDistributeuint256Amount of stETH shares that can be distributed

hashLeaf​

Get a hash of a leaf

Double hash the leaf to prevent second preimage attacks

function hashLeaf(uint256 nodeOperatorId, uint256 shares) public pure returns (bytes32);

Parameters

NameTypeDescription
nodeOperatorIduint256ID of the Node Operator
sharesuint256Amount of stETH shares

Returns

NameTypeDescription
<none>bytes32Hash of the leaf

Events​

OperatorFeeDistributed​

Emitted when fees are distributed

event OperatorFeeDistributed(uint256 indexed nodeOperatorId, uint256 shares);

DistributionDataUpdated​

Emitted when distribution data is updated

event DistributionDataUpdated(uint256 totalClaimableShares, bytes32 treeRoot, string treeCid);

DistributionLogUpdated​

Emitted when distribution log is updated

event DistributionLogUpdated(string logCid);

ModuleFeeDistributed​

It logs how many shares were distributed in the latest report

event ModuleFeeDistributed(uint256 shares);

RebateTransferred​

Emitted when rebate is transferred

event RebateTransferred(uint256 shares);

RebateRecipientSet​

Emitted when rebate recipient is set

event RebateRecipientSet(address recipient);