Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interfaces chore #368

Merged
merged 5 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 36 additions & 153 deletions src/CSAccounting.sol

Large diffs are not rendered by default.

28 changes: 4 additions & 24 deletions src/CSEarlyAdoption.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,6 @@ contract CSEarlyAdoption is ICSEarlyAdoption {

mapping(address => bool) internal _consumedAddresses;

event Consumed(address indexed member);

error InvalidProof();
error AlreadyConsumed();
error InvalidTreeRoot();
error InvalidCurveId();
error ZeroModuleAddress();
error SenderIsNotModule();

constructor(bytes32 treeRoot, uint256 curveId, address module) {
if (treeRoot == bytes32(0)) revert InvalidTreeRoot();
if (curveId == 0) revert InvalidCurveId();
Expand All @@ -35,10 +26,7 @@ contract CSEarlyAdoption is ICSEarlyAdoption {
MODULE = module;
}

/// @notice Validate EA eligibility proof and mark it as consumed
/// @dev Called only by the module
/// @param member Address to be verified alongside the proof
/// @param proof Merkle proof of EA eligibility
/// @inheritdoc ICSEarlyAdoption
function consume(address member, bytes32[] calldata proof) external {
if (msg.sender != MODULE) revert SenderIsNotModule();
if (_consumedAddresses[member]) revert AlreadyConsumed();
Expand All @@ -47,28 +35,20 @@ contract CSEarlyAdoption is ICSEarlyAdoption {
emit Consumed(member);
}

/// @notice Check if the address has already consumed EA access
/// @param member Address to check
/// @return Consumed flag
/// @inheritdoc ICSEarlyAdoption
function isConsumed(address member) external view returns (bool) {
return _consumedAddresses[member];
}

/// @notice Check is the address is eligible to consume EA access
/// @param member Address to check
/// @param proof Merkle proof of EA eligibility
/// @return Boolean flag if the proof is valid or not
/// @inheritdoc ICSEarlyAdoption
function verifyProof(
address member,
bytes32[] calldata proof
) public view returns (bool) {
return MerkleProof.verifyCalldata(proof, TREE_ROOT, hashLeaf(member));
}

/// @notice Get a hash of a leaf in EA Merkle tree
/// @param member EA member address
/// @return Hash of the leaf
/// @dev Double hash the leaf to prevent second preimage attacks
/// @inheritdoc ICSEarlyAdoption
function hashLeaf(address member) public pure returns (bytes32) {
return keccak256(bytes.concat(keccak256(abi.encode(member))));
}
Expand Down
56 changes: 6 additions & 50 deletions src/CSFeeDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,34 +40,6 @@ contract CSFeeDistributor is
/// @notice Total Amount of stETH shares available for claiming by NOs
uint256 public totalClaimableShares;

/// @dev Emitted when fees are distributed
event FeeDistributed(uint256 indexed nodeOperatorId, uint256 shares);

/// @dev Emitted when distribution data is updated
event DistributionDataUpdated(
uint256 totalClaimableShares,
bytes32 treeRoot,
string treeCid
);

/// @dev Emitted when distribution log is updated
event DistributionLogUpdated(string logCid);

error ZeroAccountingAddress();
error ZeroStEthAddress();
error ZeroAdminAddress();
error ZeroOracleAddress();
error NotAccounting();
error NotOracle();

error InvalidTreeRoot();
error InvalidTreeCID();
error InvalidLogCID();
error InvalidShares();
error InvalidProof();
error FeeSharesDecrease();
error NotEnoughShares();

constructor(address stETH, address accounting, address oracle) {
if (accounting == address(0)) revert ZeroAccountingAddress();
if (oracle == address(0)) revert ZeroOracleAddress();
Expand All @@ -87,11 +59,7 @@ contract CSFeeDistributor is
_grantRole(DEFAULT_ADMIN_ROLE, admin);
}

/// @notice Distribute fees to the Accounting in favor of the Node Operator
/// @param nodeOperatorId ID of the Node Operator
/// @param shares Total Amount of stETH shares earned as fees
/// @param proof Merkle proof of the leaf
/// @return sharesToDistribute Amount of stETH shares distributed
/// @inheritdoc ICSFeeDistributor
function distributeFees(
uint256 nodeOperatorId,
uint256 shares,
Expand All @@ -117,7 +85,7 @@ contract CSFeeDistributor is
emit FeeDistributed(nodeOperatorId, sharesToDistribute);
}

/// @notice Receive the data of the Merkle tree from the Oracle contract and process it
/// @inheritdoc ICSFeeDistributor
function processOracleReport(
bytes32 _treeRoot,
string calldata _treeCid,
Expand Down Expand Up @@ -163,10 +131,7 @@ contract CSFeeDistributor is
emit DistributionLogUpdated(_logCid);
}

/// @notice Recover ERC20 tokens (except for stETH) from the contract
/// @dev Any stETH transferred to feeDistributor is treated as a donation and can not be recovered
/// @param token Address of the ERC20 token to recover
/// @param amount Amount of the ERC20 token to recover
/// @inheritdoc AssetRecoverer
function recoverERC20(address token, uint256 amount) external override {
_onlyRecoverer();
if (token == address(STETH)) {
Expand All @@ -175,17 +140,12 @@ contract CSFeeDistributor is
AssetRecovererLib.recoverERC20(token, amount);
}

/// @notice Get the Amount of stETH shares that are pending to be distributed
/// @return pendingShares Amount shares that are pending to distribute
/// @inheritdoc ICSFeeDistributor
function pendingSharesToDistribute() external view returns (uint256) {
return STETH.sharesOf(address(this)) - totalClaimableShares;
}

/// @notice Get the Amount of stETH shares that can be distributed in favor of the Node Operator
/// @param nodeOperatorId ID of the Node Operator
/// @param shares Total Amount of stETH shares earned as fees
/// @param proof Merkle proof of the leaf
/// @return sharesToDistribute Amount of stETH shares that can be distributed
/// @inheritdoc ICSFeeDistributor
function getFeesToDistribute(
uint256 nodeOperatorId,
uint256 shares,
Expand All @@ -210,11 +170,7 @@ contract CSFeeDistributor is
}
}

/// @notice Get a hash of a leaf
/// @param nodeOperatorId ID of the Node Operator
/// @param shares Amount of stETH shares
/// @return Hash of the leaf
/// @dev Double hash the leaf to prevent second preimage attacks
/// @inheritdoc ICSFeeDistributor
function hashLeaf(
uint256 nodeOperatorId,
uint256 shares
Expand Down
53 changes: 9 additions & 44 deletions src/CSFeeOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,16 @@ import { BaseOracle } from "./lib/base-oracle/BaseOracle.sol";

import { ICSFeeDistributor } from "./interfaces/ICSFeeDistributor.sol";
import { AssetRecoverer } from "./abstract/AssetRecoverer.sol";
import { IAssetRecovererLib } from "./lib/AssetRecovererLib.sol";
import { ICSFeeOracle } from "./interfaces/ICSFeeOracle.sol";

contract CSFeeOracle is
ICSFeeOracle,
BaseOracle,
PausableUntil,
AssetRecoverer,
IAssetRecovererLib
AssetRecoverer
{
/// @notice No assets are stored in the contract

struct ReportData {
/// @dev Version of the oracle consensus rules. Current version expected
/// by the oracle can be obtained by calling getConsensusVersion().
uint256 consensusVersion;
/// @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 last frame reported.
string logCid;
/// @notice Total amount of fees distributed in the report.
uint256 distributed;
}

/// @notice An ACL role granting the permission to manage the contract (update variables).
bytes32 public constant CONTRACT_MANAGER_ROLE =
keccak256("CONTRACT_MANAGER_ROLE");
Expand All @@ -62,16 +43,6 @@ contract CSFeeOracle is
/// performance over the network computed by the off-chain oracle.
uint256 public avgPerfLeewayBP;

/// @dev Emitted when a new fee distributor contract is set
event FeeDistributorContractSet(address feeDistributorContract);

event PerfLeewaySet(uint256 valueBP);

error ZeroAdminAddress();
error ZeroFeeDistributorAddress();
error InvalidPerfLeeway();
error SenderNotAllowed();

constructor(
uint256 secondsPerSlot,
uint256 genesisTime
Expand All @@ -94,25 +65,21 @@ contract CSFeeOracle is
_setPerformanceLeeway(_avgPerfLeewayBP);
}

/// @notice Set a new fee distributor contract
/// @param feeDistributorContract Address of the new fee distributor contract
/// @inheritdoc ICSFeeOracle
function setFeeDistributorContract(
address feeDistributorContract
) external onlyRole(CONTRACT_MANAGER_ROLE) {
_setFeeDistributorContract(feeDistributorContract);
}

/// @notice Set a new performance threshold value in basis points
/// @param valueBP performance threshold in basis points
/// @inheritdoc ICSFeeOracle
function setPerformanceLeeway(
uint256 valueBP
) external onlyRole(CONTRACT_MANAGER_ROLE) {
_setPerformanceLeeway(valueBP);
}

/// @notice Submit the data for a committee report
/// @param data Data for a committee report
/// @param contractVersion Version of the oracle consensus rules
/// @inheritdoc ICSFeeOracle
function submitReportData(
ReportData calldata data,
uint256 contractVersion
Expand All @@ -129,19 +96,17 @@ contract CSFeeOracle is
_handleConsensusReportData(data);
}

/// @notice Resume accepting oracle reports
/// @inheritdoc ICSFeeOracle
function resume() external onlyRole(RESUME_ROLE) {
_resume();
}

/// @notice Pause accepting oracle reports for a `duration` seconds
/// @param duration Duration of the pause in seconds
/// @inheritdoc ICSFeeOracle
function pauseFor(uint256 duration) external onlyRole(PAUSE_ROLE) {
_pauseFor(duration);
}

/// @notice Pause accepting oracle reports until a timestamp
/// @param pauseUntilInclusive Timestamp until which the oracle reports are paused
/// @inheritdoc ICSFeeOracle
function pauseUntil(
uint256 pauseUntilInclusive
) external onlyRole(PAUSE_ROLE) {
Expand Down
Loading
Loading