From 268854531141267cf716475d27ee73933af40e93 Mon Sep 17 00:00:00 2001 From: failingtwice Date: Wed, 12 Feb 2025 12:45:25 +0500 Subject: [PATCH] feat: add more role granularity --- contracts/0.8.25/vaults/Delegation.sol | 56 ++++++++++-------------- contracts/0.8.25/vaults/VaultFactory.sol | 27 +++++++----- 2 files changed, 38 insertions(+), 45 deletions(-) diff --git a/contracts/0.8.25/vaults/Delegation.sol b/contracts/0.8.25/vaults/Delegation.sol index abe159ec4..f6b331ef7 100644 --- a/contracts/0.8.25/vaults/Delegation.sol +++ b/contracts/0.8.25/vaults/Delegation.sol @@ -10,21 +10,6 @@ import {Dashboard} from "./Dashboard.sol"; /** * @title Delegation * @notice This contract is a contract-owner of StakingVault and includes an additional delegation layer. - * - * The delegation hierarchy is as follows: - * - DEFAULT_ADMIN_ROLE is the underlying owner of StakingVault; - * - NODE_OPERATOR_MANAGER_ROLE is the node operator manager of StakingVault; and itself is the role admin, - * and the DEFAULT_ADMIN_ROLE cannot assign NODE_OPERATOR_MANAGER_ROLE; - * - NODE_OPERATOR_FEE_CLAIMER_ROLE is the role that can claim node operator fee; is assigned by NODE_OPERATOR_MANAGER_ROLE; - * - * Additionally, the following roles are assigned by DEFAULT_ADMIN_ROLE: - * - CURATOR_ROLE is the curator of StakingVault and perfoms some operations on behalf of DEFAULT_ADMIN_ROLE; - * - FUND_WITHDRAW_ROLE funds and withdraws from the StakingVault; - * - MINT_BURN_ROLE mints and burns shares of stETH backed by the StakingVault; - * - * The curator and node operator have their respective fees. - * The feeBP is the percentage (in basis points) of the StakingVault rewards. - * The unclaimed fee is the amount of ether that is owed to the curator or node operator based on the feeBP. */ contract Delegation is Dashboard { /** @@ -33,31 +18,33 @@ contract Delegation is Dashboard { uint256 private constant MAX_FEE_BP = TOTAL_BASIS_POINTS; /** - * @notice Curator role: - * - sets curator fee; - * - claims curator fee; - * - confirms confirm lifetime; - * - confirms node operator fee; - * - confirms ownership transfer; - * - pauses deposits to beacon chain; - * - resumes deposits to beacon chain. + * @notice Sets curator fee. + */ + bytes32 public constant CURATOR_FEE_SET_ROLE = keccak256("vaults.Delegation.CuratorFeeSetRole"); + + /** + * @notice Claims curator fee. */ - bytes32 public constant CURATOR_ROLE = keccak256("vaults.Delegation.CuratorRole"); + bytes32 public constant CURATOR_FEE_CLAIM_ROLE = keccak256("vaults.Delegation.CuratorFeeClaimRole"); /** * @notice Node operator manager role: * - confirms confirm lifetime; - * - confirms node operator fee; * - confirms ownership transfer; - * - assigns NODE_OPERATOR_FEE_CLAIMER_ROLE. + * - assigns NODE_OPERATOR_FEE_CONFIRM_ROLE; + * - assigns NODE_OPERATOR_FEE_CLAIM_ROLE. */ bytes32 public constant NODE_OPERATOR_MANAGER_ROLE = keccak256("vaults.Delegation.NodeOperatorManagerRole"); /** - * @notice Node operator fee claimer role: - * - claims node operator fee. + * @notice Confirms node operator fee. + */ + bytes32 public constant NODE_OPERATOR_FEE_CONFIRM_ROLE = keccak256("vaults.Delegation.NodeOperatorFeeConfirmRole"); + + /** + * @notice Claims node operator fee. */ - bytes32 public constant NODE_OPERATOR_FEE_CLAIMER_ROLE = keccak256("vaults.Delegation.NodeOperatorFeeClaimerRole"); + bytes32 public constant NODE_OPERATOR_FEE_CLAIM_ROLE = keccak256("vaults.Delegation.NodeOperatorFeeClaimRole"); /** * @notice Curator fee in basis points; combined with node operator fee cannot exceed 100%. @@ -105,7 +92,8 @@ contract Delegation is Dashboard { // at the end of the initialization _grantRole(NODE_OPERATOR_MANAGER_ROLE, _defaultAdmin); _setRoleAdmin(NODE_OPERATOR_MANAGER_ROLE, NODE_OPERATOR_MANAGER_ROLE); - _setRoleAdmin(NODE_OPERATOR_FEE_CLAIMER_ROLE, NODE_OPERATOR_MANAGER_ROLE); + _setRoleAdmin(NODE_OPERATOR_FEE_CONFIRM_ROLE, NODE_OPERATOR_MANAGER_ROLE); + _setRoleAdmin(NODE_OPERATOR_FEE_CLAIM_ROLE, NODE_OPERATOR_MANAGER_ROLE); } /** @@ -168,7 +156,7 @@ contract Delegation is Dashboard { * The function will revert if the curator fee is unclaimed. * @param _newCuratorFeeBP The new curator fee in basis points. */ - function setCuratorFeeBP(uint256 _newCuratorFeeBP) external onlyRole(DEFAULT_ADMIN_ROLE) { + function setCuratorFeeBP(uint256 _newCuratorFeeBP) external onlyRole(CURATOR_FEE_SET_ROLE) { if (_newCuratorFeeBP + nodeOperatorFeeBP > MAX_FEE_BP) revert CombinedFeesExceed100Percent(); if (curatorUnclaimedFee() > 0) revert CuratorFeeUnclaimed(); uint256 oldCuratorFeeBP = curatorFeeBP; @@ -198,7 +186,7 @@ contract Delegation is Dashboard { * @notice Claims the curator fee. * @param _recipient The address to which the curator fee will be sent. */ - function claimCuratorFee(address _recipient) external onlyRole(CURATOR_ROLE) { + function claimCuratorFee(address _recipient) external onlyRole(CURATOR_FEE_CLAIM_ROLE) { uint256 fee = curatorUnclaimedFee(); curatorFeeClaimedReport = stakingVault().latestReport(); _claimFee(_recipient, fee); @@ -210,7 +198,7 @@ contract Delegation is Dashboard { * although NODE_OPERATOR_MANAGER_ROLE is the admin role for NODE_OPERATOR_FEE_CLAIMER_ROLE. * @param _recipient The address to which the node operator fee will be sent. */ - function claimNodeOperatorFee(address _recipient) external onlyRole(NODE_OPERATOR_FEE_CLAIMER_ROLE) { + function claimNodeOperatorFee(address _recipient) external onlyRole(NODE_OPERATOR_FEE_CLAIM_ROLE) { uint256 fee = nodeOperatorUnclaimedFee(); nodeOperatorFeeClaimedReport = stakingVault().latestReport(); _claimFee(_recipient, fee); @@ -267,7 +255,7 @@ contract Delegation is Dashboard { */ function _confirmingRoles() internal pure override returns (bytes32[] memory roles) { roles = new bytes32[](2); - roles[0] = CURATOR_ROLE; + roles[0] = DEFAULT_ADMIN_ROLE; roles[1] = NODE_OPERATOR_MANAGER_ROLE; } diff --git a/contracts/0.8.25/vaults/VaultFactory.sol b/contracts/0.8.25/vaults/VaultFactory.sol index 65b0c2bbb..209a4ea4f 100644 --- a/contracts/0.8.25/vaults/VaultFactory.sol +++ b/contracts/0.8.25/vaults/VaultFactory.sol @@ -21,9 +21,11 @@ struct DelegationConfig { address depositResumer; address exitRequester; address disconnecter; - address curator; + address curatorFeeSetter; + address curatorFeeClaimer; address nodeOperatorManager; - address nodeOperatorFeeClaimer; + address nodeOperatorFeeConfirm; + address nodeOperatorFeeClaim; uint16 curatorFeeBP; uint16 nodeOperatorFeeBP; uint256 confirmLifetime; @@ -50,8 +52,6 @@ contract VaultFactory { DelegationConfig calldata _delegationConfig, bytes calldata _stakingVaultInitializerExtraParams ) external returns (IStakingVault vault, Delegation delegation) { - if (_delegationConfig.curator == address(0)) revert ZeroArgument("curator"); - // create StakingVault vault = IStakingVault(address(new BeaconProxy(BEACON, ""))); @@ -69,7 +69,8 @@ contract VaultFactory { // initialize Delegation delegation.initialize(address(this), _delegationConfig.confirmLifetime); - // setup roles + // setup roles from config + // basic permissions to the staking vault delegation.grantRole(delegation.DEFAULT_ADMIN_ROLE(), _delegationConfig.defaultAdmin); delegation.grantRole(delegation.FUND_ROLE(), _delegationConfig.funder); delegation.grantRole(delegation.WITHDRAW_ROLE(), _delegationConfig.withdrawer); @@ -80,20 +81,24 @@ contract VaultFactory { delegation.grantRole(delegation.RESUME_BEACON_CHAIN_DEPOSITS_ROLE(), _delegationConfig.depositResumer); delegation.grantRole(delegation.REQUEST_VALIDATOR_EXIT_ROLE(), _delegationConfig.exitRequester); delegation.grantRole(delegation.VOLUNTARY_DISCONNECT_ROLE(), _delegationConfig.disconnecter); - delegation.grantRole(delegation.CURATOR_ROLE(), _delegationConfig.curator); + // delegation roles + delegation.grantRole(delegation.CURATOR_FEE_SET_ROLE(), _delegationConfig.curatorFeeSetter); + delegation.grantRole(delegation.CURATOR_FEE_CLAIM_ROLE(), _delegationConfig.curatorFeeClaimer); delegation.grantRole(delegation.NODE_OPERATOR_MANAGER_ROLE(), _delegationConfig.nodeOperatorManager); - delegation.grantRole(delegation.NODE_OPERATOR_FEE_CLAIMER_ROLE(), _delegationConfig.nodeOperatorFeeClaimer); + delegation.grantRole(delegation.NODE_OPERATOR_FEE_CLAIM_ROLE(), _delegationConfig.nodeOperatorFeeClaim); + delegation.grantRole(delegation.NODE_OPERATOR_FEE_CONFIRM_ROLE(), _delegationConfig.nodeOperatorFeeConfirm); - // grant temporary roles to factory - delegation.grantRole(delegation.CURATOR_ROLE(), address(this)); - delegation.grantRole(delegation.NODE_OPERATOR_MANAGER_ROLE(), address(this)); + // grant temporary roles to factory for setting fees + delegation.grantRole(delegation.CURATOR_FEE_SET_ROLE(), address(this)); + delegation.grantRole(delegation.NODE_OPERATOR_FEE_CONFIRM_ROLE(), address(this)); // set fees delegation.setCuratorFeeBP(_delegationConfig.curatorFeeBP); delegation.setNodeOperatorFeeBP(_delegationConfig.nodeOperatorFeeBP); // revoke temporary roles from factory - delegation.revokeRole(delegation.CURATOR_ROLE(), address(this)); + delegation.revokeRole(delegation.CURATOR_FEE_SET_ROLE(), address(this)); + delegation.revokeRole(delegation.NODE_OPERATOR_FEE_CONFIRM_ROLE(), address(this)); delegation.revokeRole(delegation.NODE_OPERATOR_MANAGER_ROLE(), address(this)); delegation.revokeRole(delegation.DEFAULT_ADMIN_ROLE(), address(this));