diff --git a/src/contracts/core/AVSDirectory.sol b/src/contracts/core/AVSDirectory.sol index c1d004a8b..9c3a0a65f 100644 --- a/src/contracts/core/AVSDirectory.sol +++ b/src/contracts/core/AVSDirectory.sol @@ -56,11 +56,7 @@ contract AVSDirectory is * */ - /** - * @notice Called by the AVS's service manager contract to register an operator with the avs. - * @param operator The address of the operator to register. - * @param operatorSignature The signature, salt, and expiry of the operator's signature. - */ + /// @inheritdoc IAVSDirectory function registerOperatorToAVS( address operator, ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature @@ -107,10 +103,7 @@ contract AVSDirectory is emit OperatorAVSRegistrationStatusUpdated(operator, msg.sender, OperatorAVSRegistrationStatus.REGISTERED); } - /** - * @notice Called by an avs to deregister an operator with the avs. - * @param operator The address of the operator to deregister. - */ + /// @inheritdoc IAVSDirectory function deregisterOperatorFromAVS(address operator) external onlyWhenNotPaused(PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS) @@ -126,18 +119,12 @@ contract AVSDirectory is emit OperatorAVSRegistrationStatusUpdated(operator, msg.sender, OperatorAVSRegistrationStatus.UNREGISTERED); } - /** - * @notice Called by an avs to emit an `AVSMetadataURIUpdated` event indicating the information has updated. - * @param metadataURI The URI for metadata associated with an avs - */ + /// @inheritdoc IAVSDirectory function updateAVSMetadataURI(string calldata metadataURI) external { emit AVSMetadataURIUpdated(msg.sender, metadataURI); } - /** - * @notice Called by an operator to cancel a salt that has been used to register with an AVS. - * @param salt A unique and single use value associated with the approver signature. - */ + /// @inheritdoc IAVSDirectory function cancelSalt(bytes32 salt) external { require(!operatorSaltIsSpent[msg.sender][salt], "AVSDirectory.cancelSalt: cannot cancel spent salt"); operatorSaltIsSpent[msg.sender][salt] = true; @@ -149,13 +136,7 @@ contract AVSDirectory is * */ - /** - * @notice Calculates the digest hash to be signed by an operator to register with an AVS - * @param operator The account registering as an operator - * @param avs The address of the service manager contract for the AVS that the operator is registering to - * @param salt A unique and single use value associated with the approver signature. - * @param expiry Time after which the approver's signature becomes invalid - */ + /// @inheritdoc IAVSDirectory function calculateOperatorAVSRegistrationDigestHash( address operator, address avs, @@ -169,10 +150,7 @@ contract AVSDirectory is return digestHash; } - /** - * @notice Getter function for the current EIP-712 domain separator for this contract. - * @dev The domain separator will change in the event of a fork that changes the ChainID. - */ + /// @inheritdoc IAVSDirectory function domainSeparator() public view returns (bytes32) { if (block.chainid == ORIGINAL_CHAIN_ID) { return _DOMAIN_SEPARATOR; diff --git a/src/contracts/core/DelegationManager.sol b/src/contracts/core/DelegationManager.sol index d4d12091a..cdf71f070 100644 --- a/src/contracts/core/DelegationManager.sol +++ b/src/contracts/core/DelegationManager.sol @@ -95,15 +95,7 @@ contract DelegationManager is * */ - /** - * @notice Registers the caller as an operator in EigenLayer. - * @param registeringOperatorDetails is the `OperatorDetails` for the operator. - * @param metadataURI is a URI for the operator's metadata, i.e. a link providing more details on the operator. - * - * @dev Once an operator is registered, they cannot 'deregister' as an operator, and they will forever be considered "delegated to themself". - * @dev This function will revert if the caller is already delegated to an operator. - * @dev Note that the `metadataURI` is *never stored * and is only emitted in the `OperatorMetadataURIUpdated` event - */ + /// @inheritdoc IDelegationManager function registerAsOperator( OperatorDetails calldata registeringOperatorDetails, string calldata metadataURI @@ -118,39 +110,19 @@ contract DelegationManager is emit OperatorMetadataURIUpdated(msg.sender, metadataURI); } - /** - * @notice Updates an operator's stored `OperatorDetails`. - * @param newOperatorDetails is the updated `OperatorDetails` for the operator, to replace their current OperatorDetails`. - * - * @dev The caller must have previously registered as an operator in EigenLayer. - */ + /// @inheritdoc IDelegationManager function modifyOperatorDetails(OperatorDetails calldata newOperatorDetails) external { require(isOperator(msg.sender), "DelegationManager.modifyOperatorDetails: caller must be an operator"); _setOperatorDetails(msg.sender, newOperatorDetails); } - /** - * @notice Called by an operator to emit an `OperatorMetadataURIUpdated` event indicating the information has updated. - * @param metadataURI The URI for metadata associated with an operator - */ + /// @inheritdoc IDelegationManager function updateOperatorMetadataURI(string calldata metadataURI) external { require(isOperator(msg.sender), "DelegationManager.updateOperatorMetadataURI: caller must be an operator"); emit OperatorMetadataURIUpdated(msg.sender, metadataURI); } - /** - * @notice Caller delegates their stake to an operator. - * @param operator The account (`msg.sender`) is delegating its assets to for use in serving applications built on EigenLayer. - * @param approverSignatureAndExpiry Verifies the operator approves of this delegation - * @param approverSalt A unique single use value tied to an individual signature. - * @dev The approverSignatureAndExpiry is used in the event that: - * 1) the operator's `delegationApprover` address is set to a non-zero value. - * AND - * 2) neither the operator nor their `delegationApprover` is the `msg.sender`, since in the event that the operator - * or their delegationApprover is the `msg.sender`, then approval is assumed. - * @dev In the event that `approverSignatureAndExpiry` is not checked, its content is ignored entirely; it's recommended to use an empty input - * in this case to save on complexity + gas costs - */ + /// @inheritdoc IDelegationManager function delegateTo( address operator, SignatureWithExpiry memory approverSignatureAndExpiry, @@ -162,23 +134,7 @@ contract DelegationManager is _delegate(msg.sender, operator, approverSignatureAndExpiry, approverSalt); } - /** - * @notice Caller delegates a staker's stake to an operator with valid signatures from both parties. - * @param staker The account delegating stake to an `operator` account - * @param operator The account (`staker`) is delegating its assets to for use in serving applications built on EigenLayer. - * @param stakerSignatureAndExpiry Signed data from the staker authorizing delegating stake to an operator - * @param approverSignatureAndExpiry is a parameter that will be used for verifying that the operator approves of this delegation action in the event that: - * @param approverSalt Is a salt used to help guarantee signature uniqueness. Each salt can only be used once by a given approver. - * - * @dev If `staker` is an EOA, then `stakerSignature` is verified to be a valid ECDSA stakerSignature from `staker`, indicating their intention for this action. - * @dev If `staker` is a contract, then `stakerSignature` will be checked according to EIP-1271. - * @dev the operator's `delegationApprover` address is set to a non-zero value. - * @dev neither the operator nor their `delegationApprover` is the `msg.sender`, since in the event that the operator or their delegationApprover - * is the `msg.sender`, then approval is assumed. - * @dev This function will revert if the current `block.timestamp` is equal to or exceeds the expiry - * @dev In the case that `approverSignatureAndExpiry` is not checked, its content is ignored entirely; it's recommended to use an empty input - * in this case to save on complexity + gas costs - */ + /// @inheritdoc IDelegationManager function delegateToBySignature( address staker, address operator, @@ -211,11 +167,7 @@ contract DelegationManager is _delegate(staker, operator, approverSignatureAndExpiry, approverSalt); } - /** - * Allows the staker, the staker's operator, or that operator's delegationApprover to undelegate - * a staker from their operator. Undelegation immediately removes ALL active shares/strategies from - * both the staker and operator, and places the shares and strategies in the withdrawal queue - */ + /// @inheritdoc IDelegationManager function undelegate(address staker) external onlyWhenNotPaused(PAUSED_ENTER_WITHDRAWAL_QUEUE) @@ -268,13 +220,7 @@ contract DelegationManager is return withdrawalRoots; } - /** - * Allows a staker to withdraw some shares. Withdrawn shares/strategies are immediately removed - * from the staker. If the staker is delegated, withdrawn shares/strategies are also removed from - * their operator. - * - * All withdrawn shares/strategies are placed in a queue and can be fully withdrawn after a delay. - */ + /// @inheritdoc IDelegationManager function queueWithdrawals(QueuedWithdrawalParams[] calldata queuedWithdrawalParams) external onlyWhenNotPaused(PAUSED_ENTER_WITHDRAWAL_QUEUE) @@ -307,20 +253,7 @@ contract DelegationManager is return withdrawalRoots; } - /** - * @notice Used to complete the specified `withdrawal`. The caller must match `withdrawal.withdrawer` - * @param withdrawal The Withdrawal to complete. - * @param tokens Array in which the i-th entry specifies the `token` input to the 'withdraw' function of the i-th Strategy in the `withdrawal.strategies` array. - * This input can be provided with zero length if `receiveAsTokens` is set to 'false' (since in that case, this input will be unused) - * @param middlewareTimesIndex is the index in the operator that the staker who triggered the withdrawal was delegated to's middleware times array - * @param receiveAsTokens If true, the shares specified in the withdrawal will be withdrawn from the specified strategies themselves - * and sent to the caller, through calls to `withdrawal.strategies[i].withdraw`. If false, then the shares in the specified strategies - * will simply be transferred to the caller directly. - * @dev middlewareTimesIndex is unused, but will be used in the Slasher eventually - * @dev beaconChainETHStrategy shares are non-transferrable, so if `receiveAsTokens = false` and `withdrawal.withdrawer != withdrawal.staker`, note that - * any beaconChainETHStrategy shares in the `withdrawal` will be _returned to the staker_, rather than transferred to the withdrawer, unlike shares in - * any other strategies, which will be transferred to the withdrawer. - */ + /// @inheritdoc IDelegationManager function completeQueuedWithdrawal( Withdrawal calldata withdrawal, IERC20[] calldata tokens, @@ -330,15 +263,7 @@ contract DelegationManager is _completeQueuedWithdrawal(withdrawal, tokens, middlewareTimesIndex, receiveAsTokens); } - /** - * @notice Array-ified version of `completeQueuedWithdrawal`. - * Used to complete the specified `withdrawals`. The function caller must match `withdrawals[...].withdrawer` - * @param withdrawals The Withdrawals to complete. - * @param tokens Array of tokens for each Withdrawal. See `completeQueuedWithdrawal` for the usage of a single array. - * @param middlewareTimesIndexes One index to reference per Withdrawal. See `completeQueuedWithdrawal` for the usage of a single index. - * @param receiveAsTokens Whether or not to complete each withdrawal as tokens. See `completeQueuedWithdrawal` for the usage of a single boolean. - * @dev See `completeQueuedWithdrawal` for relevant dev tags - */ + /// @inheritdoc IDelegationManager function completeQueuedWithdrawals( Withdrawal[] calldata withdrawals, IERC20[][] calldata tokens, @@ -350,15 +275,7 @@ contract DelegationManager is } } - /** - * @notice Increases a staker's delegated share balance in a strategy. - * @param staker The address to increase the delegated shares for their operator. - * @param strategy The strategy in which to increase the delegated shares. - * @param shares The number of shares to increase. - * - * @dev *If the staker is actively delegated*, then increases the `staker`'s delegated shares in `strategy` by `shares`. Otherwise does nothing. - * @dev Callable only by the StrategyManager or EigenPodManager. - */ + /// @inheritdoc IDelegationManager function increaseDelegatedShares( address staker, IStrategy strategy, @@ -373,15 +290,7 @@ contract DelegationManager is } } - /** - * @notice Decreases a staker's delegated share balance in a strategy. - * @param staker The address to increase the delegated shares for their operator. - * @param strategy The strategy in which to decrease the delegated shares. - * @param shares The number of shares to decrease. - * - * @dev *If the staker is actively delegated*, then decreases the `staker`'s delegated shares in `strategy` by `shares`. Otherwise does nothing. - * @dev Callable only by the StrategyManager or EigenPodManager. - */ + /// @inheritdoc IDelegationManager function decreaseDelegatedShares( address staker, IStrategy strategy, @@ -402,21 +311,12 @@ contract DelegationManager is } } - /** - * @notice Owner-only function for modifying the value of the `minWithdrawalDelayBlocks` variable. - * @param newMinWithdrawalDelayBlocks new value of `minWithdrawalDelayBlocks`. - */ + /// @inheritdoc IDelegationManager function setMinWithdrawalDelayBlocks(uint256 newMinWithdrawalDelayBlocks) external onlyOwner { _setMinWithdrawalDelayBlocks(newMinWithdrawalDelayBlocks); } - /** - * @notice Called by owner to set the minimum withdrawal delay blocks for each passed in strategy - * Note that the min number of blocks to complete a withdrawal of a strategy is - * MAX(minWithdrawalDelayBlocks, strategyWithdrawalDelayBlocks[strategy]) - * @param strategies The strategies to set the minimum withdrawal delay blocks for - * @param withdrawalDelayBlocks The minimum withdrawal delay blocks to set for each strategy - */ + /// @inheritdoc IDelegationManager function setStrategyWithdrawalDelayBlocks( IStrategy[] calldata strategies, uint256[] calldata withdrawalDelayBlocks @@ -791,13 +691,7 @@ contract DelegationManager is * */ - /** - * @notice Getter function for the current EIP-712 domain separator for this contract. - * - * @dev The domain separator will change in the event of a fork that changes the ChainID. - * @dev By introducing a domain separator the DApp developers are guaranteed that there can be no signature collision. - * for more detailed information please read EIP-712. - */ + /// @inheritdoc IDelegationManager function domainSeparator() public view returns (bytes32) { if (block.chainid == ORIGINAL_CHAIN_ID) { return _DOMAIN_SEPARATOR; @@ -806,42 +700,32 @@ contract DelegationManager is } } - /** - * @notice Returns 'true' if `staker` *is* actively delegated, and 'false' otherwise. - */ + /// @inheritdoc IDelegationManager function isDelegated(address staker) public view returns (bool) { return (delegatedTo[staker] != address(0)); } - /** - * @notice Returns true is an operator has previously registered for delegation. - */ + /// @inheritdoc IDelegationManager function isOperator(address operator) public view returns (bool) { return operator != address(0) && delegatedTo[operator] == operator; } - /** - * @notice Returns the OperatorDetails struct associated with an `operator`. - */ + /// @inheritdoc IDelegationManager function operatorDetails(address operator) external view returns (OperatorDetails memory) { return _operatorDetails[operator]; } - /** - * @notice Returns the delegationApprover account for an operator - */ + /// @inheritdoc IDelegationManager function delegationApprover(address operator) external view returns (address) { return _operatorDetails[operator].delegationApprover; } - /** - * @notice Returns the stakerOptOutWindowBlocks for an operator - */ + /// @inheritdoc IDelegationManager function stakerOptOutWindowBlocks(address operator) external view returns (uint256) { return _operatorDetails[operator].stakerOptOutWindowBlocks; } - /// @notice Given array of strategies, returns array of shares for the operator + /// @inheritdoc IDelegationManager function getOperatorShares( address operator, IStrategy[] memory strategies @@ -853,10 +737,7 @@ contract DelegationManager is return shares; } - /** - * @notice Returns the number of actively-delegatable shares a staker has across all strategies. - * @dev Returns two empty arrays in the case that the Staker has no actively-delegateable shares. - */ + /// @inheritdoc IDelegationManager function getDelegatableShares(address staker) public view returns (IStrategy[] memory, uint256[] memory) { // Get currently active shares and strategies for `staker` int256 podShares = eigenPodManager.podOwnerShares(staker); @@ -902,11 +783,7 @@ contract DelegationManager is return (strategies, shares); } - /** - * @notice Given a list of strategies, return the minimum number of blocks that must pass to withdraw - * from all the inputted strategies. Return value is >= minWithdrawalDelayBlocks as this is the global min withdrawal delay. - * @param strategies The strategies to check withdrawal delays for - */ + /// @inheritdoc IDelegationManager function getWithdrawalDelay(IStrategy[] calldata strategies) public view returns (uint256) { uint256 withdrawalDelay = minWithdrawalDelayBlocks; for (uint256 i = 0; i < strategies.length; ++i) { @@ -918,17 +795,12 @@ contract DelegationManager is return withdrawalDelay; } - /// @notice Returns the keccak256 hash of `withdrawal`. + /// @inheritdoc IDelegationManager function calculateWithdrawalRoot(Withdrawal memory withdrawal) public pure returns (bytes32) { return keccak256(abi.encode(withdrawal)); } - /** - * @notice Calculates the digestHash for a `staker` to sign to delegate to an `operator` - * @param staker The signing staker - * @param operator The operator who is being delegated to - * @param expiry The desired expiry time of the staker's signature - */ + /// @inheritdoc IDelegationManager function calculateCurrentStakerDelegationDigestHash( address staker, address operator, @@ -940,13 +812,7 @@ contract DelegationManager is return calculateStakerDelegationDigestHash(staker, currentStakerNonce, operator, expiry); } - /** - * @notice Calculates the digest hash to be signed and used in the `delegateToBySignature` function - * @param staker The signing staker - * @param _stakerNonce The nonce of the staker. In practice we use the staker's current nonce, stored at `stakerNonce[staker]` - * @param operator The operator who is being delegated to - * @param expiry The desired expiry time of the staker's signature - */ + /// @inheritdoc IDelegationManager function calculateStakerDelegationDigestHash( address staker, uint256 _stakerNonce, @@ -961,14 +827,7 @@ contract DelegationManager is return stakerDigestHash; } - /** - * @notice Calculates the digest hash to be signed by the operator's delegationApprove and used in the `delegateTo` and `delegateToBySignature` functions. - * @param staker The account delegating their stake - * @param operator The account receiving delegated stake - * @param _delegationApprover the operator's `delegationApprover` who will be signing the delegationHash (in general) - * @param approverSalt A unique and single use value associated with the approver signature. - * @param expiry Time after which the approver's signature becomes invalid - */ + /// @inheritdoc IDelegationManager function calculateDelegationApprovalDigestHash( address staker, address operator, diff --git a/src/contracts/core/RewardsCoordinator.sol b/src/contracts/core/RewardsCoordinator.sol index d23330e0a..7e74a3e54 100644 --- a/src/contracts/core/RewardsCoordinator.sol +++ b/src/contracts/core/RewardsCoordinator.sol @@ -117,17 +117,7 @@ contract RewardsCoordinator is * */ - /** - * @notice Creates a new rewards submission on behalf of an AVS, to be split amongst the - * set of stakers delegated to operators who are registered to the `avs` - * @param rewardsSubmissions The rewards submissions being created - * @dev Expected to be called by the ServiceManager of the AVS on behalf of which the submission is being made - * @dev The duration of the `rewardsSubmission` cannot exceed `MAX_REWARDS_DURATION` - * @dev The tokens are sent to the `RewardsCoordinator` contract - * @dev Strategies must be in ascending order of addresses to check for duplicates - * @dev This function will revert if the `rewardsSubmission` is malformed, - * e.g. if the `strategies` and `weights` arrays are of non-equal lengths - */ + /// @inheritdoc IRewardsCoordinator function createAVSRewardsSubmission(RewardsSubmission[] calldata rewardsSubmissions) external onlyWhenNotPaused(PAUSED_AVS_REWARDS_SUBMISSION) @@ -148,12 +138,7 @@ contract RewardsCoordinator is } } - /** - * @notice similar to `createAVSRewardsSubmission` except the rewards are split amongst *all* stakers - * rather than just those delegated to operators who are registered to a single avs and is - * a permissioned call based on isRewardsForAllSubmitter mapping. - * @param rewardsSubmissions The rewards submissions being created - */ + /// @inheritdoc IRewardsCoordinator function createRewardsForAllSubmission(RewardsSubmission[] calldata rewardsSubmissions) external onlyWhenNotPaused(PAUSED_REWARDS_FOR_ALL_SUBMISSION) @@ -175,13 +160,7 @@ contract RewardsCoordinator is } } - /** - * @notice Creates a new rewards submission for all earners across all AVSs. - * Earners in this case indicating all operators and their delegated stakers. Undelegated stake - * is not rewarded from this RewardsSubmission. This interface is only callable - * by the token hopper contract from the Eigen Foundation - * @param rewardsSubmissions The rewards submissions being created - */ + /// @inheritdoc IRewardsCoordinator function createRewardsForAllEarners(RewardsSubmission[] calldata rewardsSubmissions) external onlyWhenNotPaused(PAUSED_REWARD_ALL_STAKERS_AND_OPERATORS) @@ -205,18 +184,7 @@ contract RewardsCoordinator is } } - /** - * @notice Claim rewards against a given root (read from _distributionRoots[claim.rootIndex]). - * Earnings are cumulative so earners don't have to claim against all distribution roots they have earnings for, - * they can simply claim against the latest root and the contract will calculate the difference between - * their cumulativeEarnings and cumulativeClaimed. This difference is then transferred to recipient address. - * @param claim The RewardsMerkleClaim to be processed. - * Contains the root index, earner, token leaves, and required proofs - * @param recipient The address recipient that receives the ERC20 rewards - * @dev only callable by the valid claimer, that is - * if claimerFor[claim.earner] is address(0) then only the earner can claim, otherwise only - * claimerFor[claim.earner] can claim the rewards. - */ + /// @inheritdoc IRewardsCoordinator function processClaim( RewardsMerkleClaim calldata claim, address recipient @@ -248,12 +216,7 @@ contract RewardsCoordinator is } } - /** - * @notice Creates a new distribution root. activatedAt is set to block.timestamp + activationDelay - * @param root The merkle root of the distribution - * @param rewardsCalculationEndTimestamp The timestamp until which rewards have been calculated - * @dev Only callable by the rewardsUpdater - */ + /// @inheritdoc IRewardsCoordinator function submitRoot( bytes32 root, uint32 rewardsCalculationEndTimestamp @@ -280,10 +243,7 @@ contract RewardsCoordinator is emit DistributionRootSubmitted(rootIndex, root, rewardsCalculationEndTimestamp, activatedAt); } - /** - * @notice allow the rewardsUpdater to disable/cancel a pending root submission in case of an error - * @param rootIndex The index of the root to be disabled - */ + /// @inheritdoc IRewardsCoordinator function disableRoot(uint32 rootIndex) external onlyWhenNotPaused(PAUSED_SUBMIT_DISABLE_ROOTS) onlyRewardsUpdater { require(rootIndex < _distributionRoots.length, "RewardsCoordinator.disableRoot: invalid rootIndex"); DistributionRoot storage root = _distributionRoots[rootIndex]; @@ -293,11 +253,7 @@ contract RewardsCoordinator is emit DistributionRootDisabled(rootIndex); } - /** - * @notice Sets the address of the entity that can call `processClaim` on behalf of the earner (msg.sender) - * @param claimer The address of the entity that can call `processClaim` on behalf of the earner - * @dev Only callable by the `earner` - */ + /// @inheritdoc IRewardsCoordinator function setClaimerFor(address claimer) external { address earner = msg.sender; address prevClaimer = claimerFor[earner]; @@ -305,39 +261,22 @@ contract RewardsCoordinator is emit ClaimerForSet(earner, prevClaimer, claimer); } - /** - * @notice Sets the delay in timestamp before a posted root can be claimed against - * @dev Only callable by the contract owner - * @param _activationDelay The new value for activationDelay - */ + /// @inheritdoc IRewardsCoordinator function setActivationDelay(uint32 _activationDelay) external onlyOwner { _setActivationDelay(_activationDelay); } - /** - * @notice Sets the global commission for all operators across all avss - * @dev Only callable by the contract owner - * @param _globalCommissionBips The commission for all operators across all avss - */ + /// @inheritdoc IRewardsCoordinator function setGlobalOperatorCommission(uint16 _globalCommissionBips) external onlyOwner { _setGlobalOperatorCommission(_globalCommissionBips); } - /** - * @notice Sets the permissioned `rewardsUpdater` address which can post new roots - * @dev Only callable by the contract owner - * @param _rewardsUpdater The address of the new rewardsUpdater - */ + /// @inheritdoc IRewardsCoordinator function setRewardsUpdater(address _rewardsUpdater) external onlyOwner { _setRewardsUpdater(_rewardsUpdater); } - /** - * @notice Sets the permissioned `rewardsForAllSubmitter` address which can submit createRewardsForAllSubmission - * @dev Only callable by the contract owner - * @param _submitter The address of the rewardsForAllSubmitter - * @param _newValue The new value for isRewardsForAllSubmitter - */ + /// @inheritdoc IRewardsCoordinator function setRewardsForAllSubmitter(address _submitter, bool _newValue) external onlyOwner { bool prevValue = isRewardsForAllSubmitter[_submitter]; emit RewardsForAllSubmitterSet(_submitter, prevValue, _newValue); @@ -521,44 +460,43 @@ contract RewardsCoordinator is * */ - /// @notice return the hash of the earner's leaf + /// @inheritdoc IRewardsCoordinator function calculateEarnerLeafHash(EarnerTreeMerkleLeaf calldata leaf) public pure returns (bytes32) { return keccak256(abi.encodePacked(EARNER_LEAF_SALT, leaf.earner, leaf.earnerTokenRoot)); } - /// @notice returns the hash of the earner's token leaf + /// @inheritdoc IRewardsCoordinator function calculateTokenLeafHash(TokenTreeMerkleLeaf calldata leaf) public pure returns (bytes32) { return keccak256(abi.encodePacked(TOKEN_LEAF_SALT, leaf.token, leaf.cumulativeEarnings)); } - /// @notice returns 'true' if the claim would currently pass the check in `processClaims` - /// but will revert if not valid + /// @inheritdoc IRewardsCoordinator function checkClaim(RewardsMerkleClaim calldata claim) public view returns (bool) { _checkClaim(claim, _distributionRoots[claim.rootIndex]); return true; } - /// @notice the commission for a specific operator for a specific avs - /// NOTE: Currently unused and simply returns the globalOperatorCommissionBips value but will be used in future release + /// @inheritdoc IRewardsCoordinator function operatorCommissionBips(address operator, address avs) external view returns (uint16) { return globalOperatorCommissionBips; } + /// @inheritdoc IRewardsCoordinator function getDistributionRootsLength() public view returns (uint256) { return _distributionRoots.length; } + /// @inheritdoc IRewardsCoordinator function getDistributionRootAtIndex(uint256 index) external view returns (DistributionRoot memory) { return _distributionRoots[index]; } - /// @notice loop through the distribution roots from reverse and get latest root that is not disabled + /// @inheritdoc IRewardsCoordinator function getCurrentDistributionRoot() external view returns (DistributionRoot memory) { return _distributionRoots[_distributionRoots.length - 1]; } - /// @notice loop through the distribution roots from reverse and get latest root that is not disabled and activated - /// i.e. a root that can be claimed against + /// @inheritdoc IRewardsCoordinator function getCurrentClaimableDistributionRoot() external view returns (DistributionRoot memory) { for (uint256 i = _distributionRoots.length; i > 0; i--) { DistributionRoot memory root = _distributionRoots[i - 1]; @@ -568,7 +506,7 @@ contract RewardsCoordinator is } } - /// @notice loop through distribution roots from reverse and return hash + /// @inheritdoc IRewardsCoordinator function getRootIndexFromHash(bytes32 rootHash) public view returns (uint32) { for (uint32 i = uint32(_distributionRoots.length); i > 0; i--) { if (_distributionRoots[i - 1].root == rootHash) { @@ -578,13 +516,7 @@ contract RewardsCoordinator is revert("RewardsCoordinator.getRootIndexFromHash: root not found"); } - /** - * @notice Getter function for the current EIP-712 domain separator for this contract. - * - * @dev The domain separator will change in the event of a fork that changes the ChainID. - * @dev By introducing a domain separator the DApp developers are guaranteed that there can be no signature collision. - * for more detailed information please read EIP-712. - */ + /// @inheritdoc IRewardsCoordinator function domainSeparator() public view returns (bytes32) { if (block.chainid == ORIGINAL_CHAIN_ID) { return _DOMAIN_SEPARATOR; diff --git a/src/contracts/core/StrategyManager.sol b/src/contracts/core/StrategyManager.sol index ddc36a032..4deeb4a97 100644 --- a/src/contracts/core/StrategyManager.sol +++ b/src/contracts/core/StrategyManager.sol @@ -90,17 +90,7 @@ contract StrategyManager is _setStrategyWhitelister(initialStrategyWhitelister); } - /** - * @notice Deposits `amount` of `token` into the specified `strategy`, with the resultant shares credited to `msg.sender` - * @param strategy is the specified strategy where deposit is to be made, - * @param token is the denomination in which the deposit is to be made, - * @param amount is the amount of token to be deposited in the strategy by the staker - * @return shares The amount of new shares in the `strategy` created as part of the action. - * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf. - * - * WARNING: Depositing tokens that allow reentrancy (eg. ERC-777) into a strategy is not recommended. This can lead to attack vectors - * where the token balance and corresponding strategy shares are not in sync upon reentrancy. - */ + /// @inheritdoc IStrategyManager function depositIntoStrategy( IStrategy strategy, IERC20 token, @@ -109,27 +99,7 @@ contract StrategyManager is shares = _depositIntoStrategy(msg.sender, strategy, token, amount); } - /** - * @notice Used for depositing an asset into the specified strategy with the resultant shares credited to `staker`, - * who must sign off on the action. - * Note that the assets are transferred out/from the `msg.sender`, not from the `staker`; this function is explicitly designed - * purely to help one address deposit 'for' another. - * @param strategy is the specified strategy where deposit is to be made, - * @param token is the denomination in which the deposit is to be made, - * @param amount is the amount of token to be deposited in the strategy by the staker - * @param staker the staker that the deposited assets will be credited to - * @param expiry the timestamp at which the signature expires - * @param signature is a valid signature from the `staker`. either an ECDSA signature if the `staker` is an EOA, or data to forward - * following EIP-1271 if the `staker` is a contract - * @return shares The amount of new shares in the `strategy` created as part of the action. - * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf. - * @dev A signature is required for this function to eliminate the possibility of griefing attacks, specifically those - * targeting stakers who may be attempting to undelegate. - * @dev Cannot be called if thirdPartyTransfersForbidden is set to true for this strategy - * - * WARNING: Depositing tokens that allow reentrancy (eg. ERC-777) into a strategy is not recommended. This can lead to attack vectors - * where the token balance and corresponding strategy shares are not in sync upon reentrancy - */ + /// @inheritdoc IStrategyManager function depositIntoStrategyWithSignature( IStrategy strategy, IERC20 token, @@ -165,12 +135,12 @@ contract StrategyManager is shares = _depositIntoStrategy(staker, strategy, token, amount); } - /// @notice Used by the DelegationManager to remove a Staker's shares from a particular strategy when entering the withdrawal queue + /// @inheritdoc IStrategyManager function removeShares(address staker, IStrategy strategy, uint256 shares) external onlyDelegationManager { _removeShares(staker, strategy, shares); } - /// @notice Used by the DelegationManager to award a Staker some shares that have passed through the withdrawal queue + /// @inheritdoc IStrategyManager function addShares( address staker, IERC20 token, @@ -180,7 +150,7 @@ contract StrategyManager is _addShares(staker, token, strategy, shares); } - /// @notice Used by the DelegationManager to convert withdrawn shares to tokens and send them to a recipient + /// @inheritdoc IStrategyManager function withdrawSharesAsTokens( address recipient, IStrategy strategy, @@ -190,30 +160,17 @@ contract StrategyManager is strategy.withdraw(recipient, token, shares); } - /** - * If true for a strategy, a user cannot depositIntoStrategyWithSignature into that strategy for another staker - * and also when performing DelegationManager.queueWithdrawals, a staker can only withdraw to themselves. - * Defaulted to false for all existing strategies. - * @param strategy The strategy to set `thirdPartyTransfersForbidden` value to - * @param value bool value to set `thirdPartyTransfersForbidden` to - */ + /// @inheritdoc IStrategyManager function setThirdPartyTransfersForbidden(IStrategy strategy, bool value) external onlyStrategyWhitelister { _setThirdPartyTransfersForbidden(strategy, value); } - /** - * @notice Owner-only function to change the `strategyWhitelister` address. - * @param newStrategyWhitelister new address for the `strategyWhitelister`. - */ + /// @inheritdoc IStrategyManager function setStrategyWhitelister(address newStrategyWhitelister) external onlyOwner { _setStrategyWhitelister(newStrategyWhitelister); } - /** - * @notice Owner-only function that adds the provided Strategies to the 'whitelist' of strategies that stakers can deposit into - * @param strategiesToWhitelist Strategies that will be added to the `strategyIsWhitelistedForDeposit` mapping (if they aren't in it already) - * @param thirdPartyTransfersForbiddenValues bool values to set `thirdPartyTransfersForbidden` to for each strategy - */ + /// @inheritdoc IStrategyManager function addStrategiesToDepositWhitelist( IStrategy[] calldata strategiesToWhitelist, bool[] calldata thirdPartyTransfersForbiddenValues @@ -236,10 +193,7 @@ contract StrategyManager is } } - /** - * @notice Owner-only function that removes the provided Strategies from the 'whitelist' of strategies that stakers can deposit into - * @param strategiesToRemoveFromWhitelist Strategies that will be removed to the `strategyIsWhitelistedForDeposit` mapping (if they are in it) - */ + /// @inheritdoc IStrategyManager function removeStrategiesFromDepositWhitelist(IStrategy[] calldata strategiesToRemoveFromWhitelist) external onlyStrategyWhitelister @@ -402,11 +356,8 @@ contract StrategyManager is } // VIEW FUNCTIONS - /** - * @notice Get all details on the staker's deposits and corresponding shares - * @param staker The staker of interest, whose deposits this function will fetch - * @return (staker's strategies, shares in these strategies) - */ + + /// @inheritdoc IStrategyManager function getDeposits(address staker) external view returns (IStrategy[] memory, uint256[] memory) { uint256 strategiesLength = stakerStrategyList[staker].length; uint256[] memory shares = new uint256[](strategiesLength); @@ -425,10 +376,7 @@ contract StrategyManager is return stakerStrategyList[staker].length; } - /** - * @notice Getter function for the current EIP-712 domain separator for this contract. - * @dev The domain separator will change in the event of a fork that changes the ChainID. - */ + /// @inheritdoc IStrategyManager function domainSeparator() public view returns (bytes32) { if (block.chainid == ORIGINAL_CHAIN_ID) { return _DOMAIN_SEPARATOR; diff --git a/src/contracts/interfaces/IAVSDirectory.sol b/src/contracts/interfaces/IAVSDirectory.sol index b35cabc99..2c3f767d8 100644 --- a/src/contracts/interfaces/IAVSDirectory.sol +++ b/src/contracts/interfaces/IAVSDirectory.sol @@ -23,7 +23,7 @@ interface IAVSDirectory is ISignatureUtils { ); /** - * @notice Called by an avs to register an operator with the avs. + * @notice Called by the AVS's service manager contract to register an operator with the avs. * @param operator The address of the operator to register. * @param operatorSignature The signature, salt, and expiry of the operator's signature. */ @@ -54,7 +54,7 @@ interface IAVSDirectory is ISignatureUtils { /** * @notice Calculates the digest hash to be signed by an operator to register with an AVS * @param operator The account registering as an operator - * @param avs The AVS the operator is registering to + * @param avs The address of the service manager contract for the AVS that the operator is registering to * @param salt A unique and single use value associated with the approver signature. * @param expiry Time after which the approver's signature becomes invalid */ @@ -67,4 +67,19 @@ interface IAVSDirectory is ISignatureUtils { /// @notice The EIP-712 typehash for the Registration struct used by the contract function OPERATOR_AVS_REGISTRATION_TYPEHASH() external view returns (bytes32); + + /** + * @notice Called by an operator to cancel a salt that has been used to register with an AVS. + * @param salt A unique and single use value associated with the approver signature. + */ + function cancelSalt(bytes32 salt) external; + + /** + * @notice Getter function for the current EIP-712 domain separator for this contract. + * + * @dev The domain separator will change in the event of a fork that changes the ChainID. + * @dev By introducing a domain separator the DApp developers are guaranteed that there can be no signature collision. + * for more detailed information please read EIP-712. + */ + function domainSeparator() external view returns (bytes32); } diff --git a/src/contracts/interfaces/IDelegationManager.sol b/src/contracts/interfaces/IDelegationManager.sol index dc42416b6..2fcb8d03d 100644 --- a/src/contracts/interfaces/IDelegationManager.sol +++ b/src/contracts/interfaces/IDelegationManager.sol @@ -148,6 +148,7 @@ interface IDelegationManager is ISignatureUtils { * @param metadataURI is a URI for the operator's metadata, i.e. a link providing more details on the operator. * * @dev Once an operator is registered, they cannot 'deregister' as an operator, and they will forever be considered "delegated to themself". + * @dev This function will revert if the caller is already delegated to an operator. * @dev Note that the `metadataURI` is *never stored * and is only emitted in the `OperatorMetadataURIUpdated` event */ function registerAsOperator( @@ -246,7 +247,7 @@ interface IDelegationManager is ISignatureUtils { * @param receiveAsTokens If true, the shares specified in the withdrawal will be withdrawn from the specified strategies themselves * and sent to the caller, through calls to `withdrawal.strategies[i].withdraw`. If false, then the shares in the specified strategies * will simply be transferred to the caller directly. - * @dev middlewareTimesIndex should be calculated off chain before calling this function by finding the first index that satisfies `slasher.canWithdraw` + * @dev middlewareTimesIndex is unused, but will be used in the Slasher eventually * @dev beaconChainETHStrategy shares are non-transferrable, so if `receiveAsTokens = false` and `withdrawal.withdrawer != withdrawal.staker`, note that * any beaconChainETHStrategy shares in the `withdrawal` will be _returned to the staker_, rather than transferred to the withdrawer, unlike shares in * any other strategies, which will be transferred to the withdrawer. @@ -296,6 +297,21 @@ interface IDelegationManager is ISignatureUtils { */ function decreaseDelegatedShares(address staker, IStrategy strategy, uint256 shares) external; + /** + * @notice Owner-only function for modifying the value of the `minWithdrawalDelayBlocks` variable. + * @param newMinWithdrawalDelayBlocks new value of `minWithdrawalDelayBlocks`. + */ + function setMinWithdrawalDelayBlocks(uint256 newMinWithdrawalDelayBlocks) external; + + /** + * @notice Called by owner to set the minimum withdrawal delay blocks for each passed in strategy + * Note that the min number of blocks to complete a withdrawal of a strategy is + * MAX(minWithdrawalDelayBlocks, strategyWithdrawalDelayBlocks[strategy]) + * @param strategies The strategies to set the minimum withdrawal delay blocks for + * @param withdrawalDelayBlocks The minimum withdrawal delay blocks to set for each strategy + */ + function setStrategyWithdrawalDelayBlocks(IStrategy[] calldata strategies, uint256[] calldata withdrawalDelayBlocks) external; + /** * @notice returns the address of the operator that `staker` is delegated to. * @notice Mapping: staker => operator whom the staker is currently delegated to. @@ -342,6 +358,13 @@ interface IDelegationManager is ISignatureUtils { */ function operatorShares(address operator, IStrategy strategy) external view returns (uint256); + + /** + * @notice Returns the number of actively-delegatable shares a staker has across all strategies. + * @dev Returns two empty arrays in the case that the Staker has no actively-delegateable shares. + */ + function getDelegatableShares(address staker) external view returns (IStrategy[] memory, uint256[] memory); + /** * @notice Returns 'true' if `staker` *is* actively delegated, and 'false' otherwise. */ diff --git a/src/contracts/interfaces/IRewardsCoordinator.sol b/src/contracts/interfaces/IRewardsCoordinator.sol index d3f5beaf2..933758618 100644 --- a/src/contracts/interfaces/IRewardsCoordinator.sol +++ b/src/contracts/interfaces/IRewardsCoordinator.sol @@ -271,6 +271,7 @@ interface IRewardsCoordinator { * @notice similar to `createAVSRewardsSubmission` except the rewards are split amongst *all* stakers * rather than just those delegated to operators who are registered to a single avs and is * a permissioned call based on isRewardsForAllSubmitter mapping. + * @param rewardsSubmission The rewards submission being created */ function createRewardsForAllSubmission(RewardsSubmission[] calldata rewardsSubmission) external; @@ -300,7 +301,7 @@ interface IRewardsCoordinator { /** * @notice Creates a new distribution root. activatedAt is set to block.timestamp + activationDelay * @param root The merkle root of the distribution - * @param rewardsCalculationEndTimestamp The timestamp (seconds) until which rewards have been calculated + * @param rewardsCalculationEndTimestamp The timestamp until which rewards have been calculated * @dev Only callable by the rewardsUpdater */ function submitRoot(bytes32 root, uint32 rewardsCalculationEndTimestamp) external; @@ -313,15 +314,15 @@ interface IRewardsCoordinator { /** * @notice Sets the address of the entity that can call `processClaim` on behalf of the earner (msg.sender) - * @param claimer The address of the entity that can claim rewards on behalf of the earner + * @param claimer The address of the entity that can call `processClaim` on behalf of the earner * @dev Only callable by the `earner` */ function setClaimerFor(address claimer) external; /** * @notice Sets the delay in timestamp before a posted root can be claimed against - * @param _activationDelay Delay in timestamp (seconds) before a posted root can be claimed against * @dev Only callable by the contract owner + * @param _activationDelay The new value for activationDelay */ function setActivationDelay(uint32 _activationDelay) external; @@ -335,6 +336,7 @@ interface IRewardsCoordinator { /** * @notice Sets the permissioned `rewardsUpdater` address which can post new roots * @dev Only callable by the contract owner + * @param _rewardsUpdater The address of the new rewardsUpdater */ function setRewardsUpdater(address _rewardsUpdater) external; @@ -345,4 +347,13 @@ interface IRewardsCoordinator { * @param _newValue The new value for isRewardsForAllSubmitter */ function setRewardsForAllSubmitter(address _submitter, bool _newValue) external; + + /** + * @notice Getter function for the current EIP-712 domain separator for this contract. + * + * @dev The domain separator will change in the event of a fork that changes the ChainID. + * @dev By introducing a domain separator the DApp developers are guaranteed that there can be no signature collision. + * for more detailed information please read EIP-712. + */ + function domainSeparator() external view returns (bytes32); } diff --git a/src/contracts/interfaces/IStrategyManager.sol b/src/contracts/interfaces/IStrategyManager.sol index 565b301cd..784bb1c46 100644 --- a/src/contracts/interfaces/IStrategyManager.sol +++ b/src/contracts/interfaces/IStrategyManager.sol @@ -92,6 +92,7 @@ interface IStrategyManager { /** * @notice Get all details on the staker's deposits and corresponding shares + * @param staker The staker of interest, whose deposits this function will fetch * @return (staker's strategies, shares in these strategies) */ function getDeposits(address staker) external view returns (IStrategy[] memory, uint256[] memory); @@ -139,9 +140,21 @@ interface IStrategyManager { /// @notice Returns bool for whether or not `strategy` is whitelisted for deposit function strategyIsWhitelistedForDeposit(IStrategy strategy) external view returns (bool); + /** + * @notice Owner-only function to change the `strategyWhitelister` address. + * @param newStrategyWhitelister new address for the `strategyWhitelister`. + */ + function setStrategyWhitelister(address newStrategyWhitelister) external; + /** * @notice Returns bool for whether or not `strategy` enables credit transfers. i.e enabling * depositIntoStrategyWithSignature calls or queueing withdrawals to a different address than the staker. */ function thirdPartyTransfersForbidden(IStrategy strategy) external view returns (bool); + + /** + * @notice Getter function for the current EIP-712 domain separator for this contract. + * @dev The domain separator will change in the event of a fork that changes the ChainID. + */ + function domainSeparator() external view returns (bytes32); } diff --git a/src/test/mocks/DelegationManagerMock.sol b/src/test/mocks/DelegationManagerMock.sol index 4fa56d087..7facde3a0 100644 --- a/src/test/mocks/DelegationManagerMock.sol +++ b/src/test/mocks/DelegationManagerMock.sol @@ -10,6 +10,12 @@ contract DelegationManagerMock is IDelegationManager, Test { mapping(address => bool) public isOperator; mapping(address => mapping(IStrategy => uint256)) public operatorShares; + function getDelegatableShares(address staker) external view returns (IStrategy[] memory, uint256[] memory) {} + + function setMinWithdrawalDelayBlocks(uint256 newMinWithdrawalDelayBlocks) external {} + + function setStrategyWithdrawalDelayBlocks(IStrategy[] calldata strategies, uint256[] calldata withdrawalDelayBlocks) external {} + function setIsOperator(address operator, bool _isOperatorReturnValue) external { isOperator[operator] = _isOperatorReturnValue; } @@ -136,8 +142,6 @@ contract DelegationManagerMock is IDelegationManager, Test { function OPERATOR_AVS_REGISTRATION_TYPEHASH() external view returns (bytes32) {} - function domainSeparator() external view returns (bytes32) {} - function cumulativeWithdrawalsQueued(address staker) external view returns (uint256) {} function calculateWithdrawalRoot(Withdrawal memory withdrawal) external pure returns (bytes32) {} @@ -148,6 +152,8 @@ contract DelegationManagerMock is IDelegationManager, Test { function operatorSaltIsSpent(address avs, bytes32 salt) external view returns (bool) {} + function domainSeparator() external view returns (bytes32) {} + function queueWithdrawals( QueuedWithdrawalParams[] calldata queuedWithdrawalParams ) external returns (bytes32[] memory) {} diff --git a/src/test/mocks/StrategyManagerMock.sol b/src/test/mocks/StrategyManagerMock.sol index cefd175fa..4a5f39cb2 100644 --- a/src/test/mocks/StrategyManagerMock.sol +++ b/src/test/mocks/StrategyManagerMock.sol @@ -55,6 +55,8 @@ contract StrategyManagerMock is function recordBeaconChainETHBalanceUpdate(address overcommittedPodOwner, uint256 beaconChainETHStrategyIndex, int256 sharesDelta) external{} + function setStrategyWhitelister(address newStrategyWhitelister) external {} + function depositIntoStrategyWithSignature( IStrategy strategy, IERC20 token, @@ -122,6 +124,8 @@ contract StrategyManagerMock is // function withdrawalDelayBlocks() external view returns (uint256) {} + function domainSeparator() external view returns (bytes32) {} + function addStrategiesToDepositWhitelist( IStrategy[] calldata strategiesToWhitelist, bool[] calldata thirdPartyTransfersForbiddenValues