Skip to content

Commit

Permalink
feat: Add distribution data history
Browse files Browse the repository at this point in the history
  • Loading branch information
dgusakov committed Jan 15, 2025
1 parent b338668 commit a140987
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 40 deletions.
45 changes: 37 additions & 8 deletions src/CSFeeDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ contract CSFeeDistributor is
address public immutable ACCOUNTING;
address public immutable ORACLE;

/// @notice Merkle Tree root
/// @notice The latest Merkle Tree root
bytes32 public treeRoot;

/// @notice CID of the published Merkle tree
/// @notice CID of the last published Merkle tree
string public treeCid;

/// @notice CID of the file with log of the last frame reported
/// @notice CID of the file with log for the last frame reported
string public logCid;

/// @notice Amount of stETH shares sent to the Accounting in favor of the NO
Expand All @@ -40,6 +40,12 @@ contract CSFeeDistributor is
/// @notice Total Amount of stETH shares available for claiming by NOs
uint256 public totalClaimableShares;

/// @notice Array of the distribution data history
mapping(uint256 => DistributionData) internal _distributionDataHistory;

/// @notice The number of _distributionDataHistory records
uint256 public distributionDataHistoryCount;

constructor(address stETH, address accounting, address oracle) {
if (accounting == address(0)) revert ZeroAccountingAddress();
if (oracle == address(0)) revert ZeroOracleAddress();
Expand Down Expand Up @@ -90,16 +96,18 @@ contract CSFeeDistributor is
bytes32 _treeRoot,
string calldata _treeCid,
string calldata _logCid,
uint256 distributed
uint256 _distributedShares,
uint256 refSlot
) external {
if (msg.sender != ORACLE) revert NotOracle();
if (
totalClaimableShares + distributed > STETH.sharesOf(address(this))
totalClaimableShares + _distributedShares >
STETH.sharesOf(address(this))
) {
revert InvalidShares();
}

if (distributed > 0) {
if (_distributedShares > 0) {
if (bytes(_treeCid).length == 0) revert InvalidTreeCID();
if (keccak256(bytes(_treeCid)) == keccak256(bytes(treeCid)))
revert InvalidTreeCID();
Expand All @@ -108,7 +116,7 @@ contract CSFeeDistributor is

// Doesn't overflow because of the very first check.
unchecked {
totalClaimableShares += distributed;
totalClaimableShares += _distributedShares;
}

treeRoot = _treeRoot;
Expand All @@ -121,7 +129,7 @@ contract CSFeeDistributor is
);
}

emit ModuleFeeDistributed(distributed);
emit ModuleFeeDistributed(_distributedShares);

// NOTE: Make sure off-chain tooling provides a distinct CID of a log even for empty reports, e.g. by mixing
// in a frame identifier such as reference slot to a file.
Expand All @@ -131,6 +139,20 @@ contract CSFeeDistributor is

logCid = _logCid;
emit DistributionLogUpdated(_logCid);

_distributionDataHistory[
distributionDataHistoryCount
] = DistributionData({
refSlot: refSlot,
treeRoot: treeRoot,
treeCid: treeCid,
logCid: _logCid,
distributed: _distributedShares
});

unchecked {
++distributionDataHistoryCount;
}
}

/// @inheritdoc AssetRecoverer
Expand All @@ -147,6 +169,13 @@ contract CSFeeDistributor is
return STETH.sharesOf(address(this)) - totalClaimableShares;
}

/// @inheritdoc ICSFeeDistributor
function getHistoricalDistributionData(
uint256 index
) external view returns (DistributionData memory) {
return _distributionDataHistory[index];
}

/// @inheritdoc ICSFeeDistributor
function getFeesToDistribute(
uint256 nodeOperatorId,
Expand Down
13 changes: 7 additions & 6 deletions src/CSFeeOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,13 @@ contract CSFeeOracle is
}

function _handleConsensusReportData(ReportData calldata data) internal {
feeDistributor.processOracleReport(
data.treeRoot,
data.treeCid,
data.logCid,
data.distributed
);
feeDistributor.processOracleReport({
_treeRoot: data.treeRoot,
_treeCid: data.treeCid,
_logCid: data.logCid,
_distributedShares: data.distributed,
refSlot: data.refSlot
});
}

function _checkMsgSenderIsAllowedToSubmitData() internal view {
Expand Down
27 changes: 26 additions & 1 deletion src/interfaces/ICSFeeDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ import { IStETH } from "./IStETH.sol";
pragma solidity 0.8.24;

interface ICSFeeDistributor is IAssetRecovererLib {
struct DistributionData {
/// @dev Reference slot for which the report was calculated. If the slot
/// contains a block, the state being reported should include all state
/// changes resulting from that block. The epoch containing the slot
/// should be finalized prior to calculating the report.
uint256 refSlot;
/// @notice Merkle Tree root.
bytes32 treeRoot;
/// @notice CID of the published Merkle tree.
string treeCid;
/// @notice CID of the file with log of the frame reported.
string logCid;
/// @notice Total amount of fees distributed in the report.
uint256 distributed;
}

/// @dev Emitted when fees are distributed
event OperatorFeeDistributed(
uint256 indexed nodeOperatorId,
Expand Down Expand Up @@ -85,17 +101,26 @@ interface ICSFeeDistributor is IAssetRecovererLib {
/// @param _treeRoot Root of the Merkle tree
/// @param _treeCid an IPFS CID of the tree
/// @param _logCid an IPFS CID of the log
/// @param _distributedShares an amount of the distributed shares
/// @param refSlot refSlot of the report
function processOracleReport(
bytes32 _treeRoot,
string calldata _treeCid,
string calldata _logCid,
uint256 _distributedShares
uint256 _distributedShares,
uint256 refSlot
) external;

/// @notice Get the Amount of stETH shares that are pending to be distributed
/// @return pendingShares Amount shares that are pending to distribute
function pendingSharesToDistribute() external view returns (uint256);

/// @notice Get the historical record of distribution data
/// @return index Historical entry index
function getHistoricalDistributionData(
uint256 index
) external view returns (DistributionData memory);

/// @notice Get a hash of a leaf
/// @param nodeOperatorId ID of the Node Operator
/// @param shares Amount of stETH shares
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/ICSFeeOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface ICSFeeOracle is IAssetRecovererLib {
bytes32 treeRoot;
/// @notice CID of the published Merkle tree.
string treeCid;
/// @notice CID of the file with log of the last frame reported.
/// @notice CID of the file with log of the frame reported.
string logCid;
/// @notice Total amount of fees distributed in the report.
uint256 distributed;
Expand Down
Loading

0 comments on commit a140987

Please sign in to comment.