Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"contracts/delegation/providers/eigenlayer/EigenOperator.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import { IEigenOperator } from "../../../interfaces/IEigenOperator.sol";
import { IEigenServiceManager } from "../../../interfaces/IEigenServiceManager.sol";
import { EigenOperatorStorageUtils } from "../../../storage/EigenOperatorStorageUtils.sol";
import { IAllocationManager } from "./interfaces/IAllocationManager.sol";
import { IDelegationManager } from "./interfaces/IDelegationManager.sol";
import { IRewardsCoordinator } from "./interfaces/IRewardsCoordinator.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
/// @title EigenOperator
/// @author weso, Cap Labs
/// @notice This contract manages the eigen operator as proxy to disable some functionality for operators
contract EigenOperator is IEigenOperator, Initializable, EigenOperatorStorageUtils {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/// @inheritdoc IEigenOperator
function initialize(address _serviceManager, address _operator, string calldata _metadata) external initializer {
EigenOperatorStorage storage $ = getEigenOperatorStorage();
$.serviceManager = _serviceManager;
$.operator = _operator;
$.totpPeriod = 28 days; // Arbitrary value
// Fetch the eigen addresses
IEigenServiceManager.EigenAddresses memory eigenAddresses =
IEigenServiceManager(_serviceManager).eigenAddresses();
$.allocationManager = eigenAddresses.allocationManager;
$.delegationManager = eigenAddresses.delegationManager;
$.rewardsCoordinator = eigenAddresses.rewardsCoordinator;
// Register as an operator on delegation manager
IDelegationManager($.delegationManager).registerAsOperator(address(this), 0, _metadata);
}
/// @inheritdoc IEigenOperator
function registerOperatorSetToServiceManager(uint32 _operatorSetId, address _staker) external {
EigenOperatorStorage storage $ = getEigenOperatorStorage();
if (msg.sender != $.serviceManager) revert NotServiceManager();
if ($.restaker != address(0)) revert AlreadyRegistered();
if (_staker == address(0)) revert ZeroAddress();
/// @dev The digest is calculated using the staker and operator addresses
bytes32 digest = calculateTotpDigestHash(_staker, address(this));
/// @dev Allowlist the digest for delegation approval from the staker
$.allowlistedDigests[digest] = true;
$.restaker = _staker;
// Build the register params
uint32[] memory operatorSetIds = new uint32[](1);
operatorSetIds[0] = _operatorSetId;
IAllocationManager.RegisterParams memory params =
IAllocationManager.RegisterParams({ avs: msg.sender, operatorSetIds: operatorSetIds, data: "" });
// 1. Register the operator set to the service manager, which in turn calls RegisterOperator on the Eigen Service Manager
IAllocationManager($.allocationManager).registerForOperatorSets(address(this), params);
// 2. Set the operator split to 0, all rewards go to restakers
IRewardsCoordinator($.rewardsCoordinator).setOperatorAVSSplit(address(this), msg.sender, 0);
}
/// @inheritdoc IEigenOperator
function allocate(uint32 _operatorSetId, address _strategy) external {
EigenOperatorStorage storage $ = getEigenOperatorStorage();
if (msg.sender != $.serviceManager) revert NotServiceManager();
(, IAllocationManager.Allocation[] memory _allocations) =
IAllocationManager($.allocationManager).getStrategyAllocations(address(this), _strategy);
if (_allocations.length != 0) revert AlreadyAllocated();
// The strategy that the restakers capital is deployed to
address[] memory strategies = new address[](1);
strategies[0] = _strategy;
// Only 1 allocation so 1e18 just means everything will be allocated to the avs
uint64[] memory magnitudes = new uint64[](1);
magnitudes[0] = 1e18;
// Create the allocation params
IAllocationManager.OperatorSet memory operatorSet =
IAllocationManager.OperatorSet({ avs: msg.sender, id: _operatorSetId });
IAllocationManager.AllocateParams[] memory allocations = new IAllocationManager.AllocateParams[](1);
allocations[0] = IAllocationManager.AllocateParams({
operatorSet: operatorSet,
strategies: strategies,
newMagnitudes: magnitudes
});
// Allocates the operator set. Can only be called after ALLOCATION_CONFIGURATION_DELAY (approximately 17.5 days) has passed since registration.
IAllocationManager($.allocationManager).modifyAllocations(address(this), allocations);
}
/// @inheritdoc IEigenOperator
function updateOperatorMetadataURI(string calldata _metadataURI) external {
EigenOperatorStorage storage $ = getEigenOperatorStorage();
if (msg.sender != $.operator) revert NotOperator();
IDelegationManager($.delegationManager).updateOperatorMetadataURI(address(this), _metadataURI);
}
/// @inheritdoc IEigenOperator
function advanceTotp() external {
EigenOperatorStorage storage $ = getEigenOperatorStorage();
if (msg.sender != $.restaker) revert NotRestaker();
// If for some reason the delegation approval has expired, allowlist the new digest
// This shouldn't matter since only the restaker can call this function
bytes32 digest = calculateTotpDigestHash($.restaker, address(this));
$.allowlistedDigests[digest] = true;
}
/// @inheritdoc IEigenOperator
function eigenServiceManager() external view returns (address) {
return getEigenOperatorStorage().serviceManager;
}
/// @inheritdoc IEigenOperator
function operator() external view returns (address) {
return getEigenOperatorStorage().operator;
}
/// @inheritdoc IEigenOperator
function restaker() external view returns (address) {
return getEigenOperatorStorage().restaker;
}
/// @inheritdoc IEigenOperator
function isValidSignature(bytes32 _digest, bytes memory) external view override returns (bytes4 magicValue) {
EigenOperatorStorage storage $ = getEigenOperatorStorage();
/// If the created at epoch is > the current epoch, the operator is not allowed to delegate
uint32 createdAtEpoch = IEigenServiceManager($.serviceManager).createdAtEpoch($.operator);
uint256 calcIntervalSeconds = IEigenServiceManager($.serviceManager).calculationIntervalSeconds();
uint32 currentEpoch = uint32(block.timestamp / calcIntervalSeconds);
if (createdAtEpoch > currentEpoch) return bytes4(0xffffffff);
// This gets called by the delegation manager to check if the operator is allowed to delegate
if ($.allowlistedDigests[_digest]) {
return bytes4(0x1626ba7e); // ERC1271 magic value for valid signatures
} else {
return bytes4(0xffffffff);
}
}
/// @inheritdoc IEigenOperator
function getCurrentTotpExpiryTimestamp() public view returns (uint256) {
EigenOperatorStorage storage $ = getEigenOperatorStorage();
uint256 current = block.timestamp / $.totpPeriod;
return (current + 1) * $.totpPeriod; // End of the current period
}
/// @inheritdoc IEigenOperator
function currentTotp() public view returns (uint256) {
EigenOperatorStorage storage $ = getEigenOperatorStorage();
return block.timestamp / $.totpPeriod;
}
/// @inheritdoc IEigenOperator
function calculateTotpDigestHash(address _staker, address _operator) public view returns (bytes32) {
uint256 expiryTimestamp = getCurrentTotpExpiryTimestamp();
return IDelegationManager(getEigenOperatorStorage().delegationManager).calculateDelegationApprovalDigestHash(
_staker, _operator, address(this), bytes32(uint256(expiryTimestamp)), expiryTimestamp
);
}
}
"
},
"contracts/interfaces/IEigenOperator.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
interface IEigenOperator {
/// @dev Error thrown when the caller is not the service manager
error NotServiceManager();
/// @dev Error thrown when the caller is not the operator
error NotOperator();
/// @dev Error thrown when the operator is already allocated to a strategy
error AlreadyAllocated();
/// @dev Error thrown when the caller is not the restaker
error NotRestaker();
/// @dev Error thrown when the operator is already registered
error AlreadyRegistered();
/// @dev Error thrown when the staker is the zero address
error ZeroAddress();
/// @dev EigenOperator storage
/// @param serviceManager EigenServiceManager address
/// @param operator Eigen operator address
/// @param allocationManager EigenCloud Allocation manager address
/// @param delegationManager EigenCloud Delegation manager address
/// @param rewardsCoordinator EigenCloud Rewards coordinator address
struct EigenOperatorStorage {
address serviceManager;
address operator;
address allocationManager;
address delegationManager;
address rewardsCoordinator;
address restaker;
uint32 totpPeriod;
mapping(bytes32 => bool) allowlistedDigests;
}
/// @notice Initialize the EigenOperator
/// @param _serviceManager EigenServiceManager address
/// @param _operator Eigen operator address
/// @param _metadata Metadata URI
function initialize(address _serviceManager, address _operator, string calldata _metadata) external;
/// @notice Register an operator set to the service manager
/// @param _operatorSetId Operator set id
function registerOperatorSetToServiceManager(uint32 _operatorSetId, address _staker) external;
/// @notice Update the operator metadata URI
/// @param _metadataURI The new metadata URI
function updateOperatorMetadataURI(string calldata _metadataURI) external;
/// @notice Allocate the operator set to the strategy, called by service manager.
/// @param _operatorSetId Operator set id
/// @param _strategy Strategy address
function allocate(uint32 _operatorSetId, address _strategy) external;
/// @notice Advance the TOTP
function advanceTotp() external;
/// @notice Get the service manager
/// @return The service manager address
function eigenServiceManager() external view returns (address);
/**
* @notice Implements the IERC1271 interface to validate signatures
* @dev In this implementation, we check if the digest hash is directly allowlisted
* @param digest The digest hash containing encoded delegation information
* @return magicValue Returns the ERC1271 magic value if valid, or 0xffffffff if invalid
*/
function isValidSignature(bytes32 digest, bytes memory signature) external view returns (bytes4 magicValue);
/// @notice Get the operator
/// @return The operator or borrower address in the cap system
function operator() external view returns (address);
/// @notice Get the current TOTP
/// @return The current TOTP
function currentTotp() external view returns (uint256);
/// @notice Get the current TOTP expiry timestamp
/// @return The current TOTP expiry timestamp
function getCurrentTotpExpiryTimestamp() external view returns (uint256);
/// @notice Calculate the TOTP digest hash
/// @param _staker The staker address
/// @param _operator The operator address
/// @return The TOTP digest hash
function calculateTotpDigestHash(address _staker, address _operator) external view returns (bytes32);
/// @notice Get the restaker
/// @return The restaker address
function restaker() external view returns (address);
}
"
},
"contracts/interfaces/IEigenServiceManager.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
import { UpgradeableBeacon } from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
import { IRewardsCoordinator } from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol";
interface IEigenServiceManager {
/// @dev Invalid AVS
error InvalidAVS();
/// @dev Invalid operator set ids
error InvalidOperatorSetIds();
/// @dev Invalid operator
error InvalidOperator();
/// @dev Operator already registered
error AlreadyRegisteredOperator();
/// @dev Invalid redistribution recipient
error InvalidRedistributionRecipient();
/// @dev Zero address
error ZeroAddress();
/// @dev Operator set already created
error OperatorSetAlreadyCreated();
/// @dev Operator doesn't exist
error OperatorDoesntExist();
/// @dev Min magnitude not met
error MinMagnitudeNotMet();
/// @dev Invalid decimals
error InvalidDecimals();
/// @dev Min share not met
error MinShareNotMet();
/// @dev Zero slash
error ZeroSlash();
/// @dev Slash share too small
error SlashShareTooSmall();
/// @dev Operator registered
event OperatorRegistered(
address indexed operator, address indexed eigenOperator, address indexed avs, uint32 operatorSetId
);
/// @dev Emitted on slash
event Slash(address indexed agent, address indexed recipient, uint256 slashShare, uint48 timestamp);
/// @dev Strategy registered
event StrategyRegistered(address indexed strategy, address indexed operator);
/// @dev Epochs between distributions set
event EpochsBetweenDistributionsSet(uint32 epochsBetweenDistributions);
/// @dev Min reward amount set
event MinRewardAmountSet(uint256 minRewardAmount);
/// @dev Distributed rewards
event DistributedRewards(address indexed strategy, address indexed token, uint256 amount);
/// @dev EigenServiceManager storage
/// @param eigen Eigen addresses
/// @param oracle Oracle address
/// @param eigenOperatorInstance Eigen operator instance
/// @param epochsBetweenDistributions Epochs between distributions
/// @param nextOperatorId Next operator id
/// @param pendingRewards Pending rewards
/// @param eigenOperatorToOperator Mapping from eigen operator to operator
struct EigenServiceManagerStorage {
EigenAddresses eigen;
address oracle;
address eigenOperatorInstance;
address[] redistributionRecipients;
uint32 epochsBetweenDistributions;
uint32 nextOperatorId;
mapping(address => uint256) pendingRewardsByToken;
mapping(address => CachedOperatorData) operators;
mapping(address => address) eigenOperatorToOperator;
}
/// @dev Cached operator data
/// @param eigenOperator Eigen operator address
/// @param strategy Strategy address
/// @param createdAtEpoch Epoch at which the operator was created
/// @param operatorSetId Operator set id
/// @param pendingRewards Pending rewards
struct CachedOperatorData {
address eigenOperator;
address strategy;
uint32 createdAtEpoch;
uint32 operatorSetId;
mapping(address => uint256) pendingRewards;
mapping(address => uint32) lastDistributionEpoch;
}
/// @dev Eigen addresses
/// @param allocationManager Allocation manager address
/// @param delegationManager Delegation manager address
/// @param strategyManager Strategy manager address
/// @param rewardsCoordinator Rewards coordinator address
struct EigenAddresses {
address allocationManager;
address delegationManager;
address strategyManager;
address rewardsCoordinator;
}
/// @notice Initialize the EigenServiceManager
/// @param _accessControl Access control contract
/// @param _addresses Eigen addresses
/// @param _oracle Oracle contract
/// @param _rewardDuration Reward duration
function initialize(
address _accessControl,
EigenAddresses memory _addresses,
address _oracle,
uint32 _rewardDuration
) external;
/**
* @notice Creates a new rewards submission to the EigenLayer RewardsCoordinator contract, to be split amongst the
* set of stakers delegated to operators who are registered to this `avs`
* @param rewardsSubmissions The rewards submissions being created
* @dev Only callable by the permissioned rewardsInitiator address
* @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
* @dev This function may fail to execute with a large number of submissions due to gas limits. Use a
* smaller array of submissions if necessary.
*/
/**
* @notice Distributes rewards to the operator
* @param _operator The operator to distribute rewards to
* @param _token The token to distribute rewards for
*/
function distributeRewards(address _operator, address _token) external;
/**
* @notice Returns the coverage for an operator
* @param operator The operator to get the coverage for
* @return The coverage of the operator
*/
function coverage(address operator) external view returns (uint256);
/**
* @notice Registers an operator to the AVS, called by the Allocation Manager contract (access control set for the allocation manager).
* @param _operator The operator to register
* @param _avs The AVS to register the operator to
* @param _operatorSetIds The operator set ids to register the operator to
* @param _data Additional data
*/
function registerOperator(address _operator, address _avs, uint32[] calldata _operatorSetIds, bytes calldata _data)
external;
/**
* @notice Registers a strategy to the AVS
* @param _strategy The strategy to register
* @param _operator The operator to register the strategy to
* @param _restaker The restaker to register the strategy to
* @param _operatorMetadata The metadata for the operator
* @return _operatorSetId The operator set id
*/
function registerStrategy(address _strategy, address _operator, address _restaker, string memory _operatorMetadata)
external
returns (uint32 _operatorSetId);
/**
* @notice Slashes an operator
* @param _operator The operator to slash
* @param _recipient The recipient of the slashed collateral
* @param _slashShare The share of the slashable collateral to slash
* @param _timestamp The timestamp of the slash (unused for eigenlayer)
*/
function slash(address _operator, address _recipient, uint256 _slashShare, uint48 _timestamp) external;
/**
* @notice Allocates the operator set, is public and can be called permissionless. We would have allocated on registerStrategy but it needs to wait at least a block.
* @param _operator Operator address
*/
function allocate(address _operator) external;
/**
* @notice Returns the slashable collateral for an operator
* @param operator The operator to get the slashable collateral for
* @param timestamp The timestamp to get the slashable collateral for (unused for eigenlayer)
* @return The slashable collateral of the operator
*/
function slashableCollateral(address operator, uint48 timestamp) external view returns (uint256);
/**
* @notice Sets the epochs between distributions
* @param _epochsBetweenDistributions The epochs between distributions
*/
function setEpochsBetweenDistributions(uint32 _epochsBetweenDistributions) external;
/**
* @notice Updates the AVS metadata URI
* @param _metadataURI The new metadata URI
*/
function updateAVSMetadataURI(string calldata _metadataURI) external;
/**
* @notice Upgrades the eigen operator implementation
* @param _newImplementation The new implementation
*/
function upgradeEigenOperatorImplementation(address _newImplementation) external;
/**
* @notice Returns the eigen addresses
* @return The eigen addresses
*/
function eigenAddresses() external view returns (EigenAddresses memory);
/**
* @notice Returns the operator to strategy mapping
* @return The operator to strategy mapping
*/
function operatorToStrategy(address operator) external view returns (address);
/**
* @notice Returns the operator set id for an operator
* @param operator The operator to get the operator set id for
* @return The operator set id of the operator
*/
function operatorSetId(address operator) external view returns (uint32);
/**
* @notice Returns the epochs between distributions
* @return The epochs between distributions
*/
function epochsBetweenDistributions() external view returns (uint32);
/**
* @notice Returns the created at epoch for an operator
* @param operator The operator to get the created at epoch for
* @return The created at epoch of the operator
*/
function createdAtEpoch(address operator) external view returns (uint32);
/**
* @notice Returns the calculation interval seconds
* @return The calculation interval seconds
*/
function calculationIntervalSeconds() external view returns (uint256);
/**
* @notice Returns the pending rewards for an operator
* @param _strategy The strategy to get the pending rewards for
* @param _token The token to get the pending rewards for
* @return The pending rewards of the strategy
*/
function pendingRewards(address _strategy, address _token) external view returns (uint256);
/**
* @notice Returns the eigen operator for an operator
* @param _operator The operator to get the eigen operator for
* @return The eigen operator of the operator
*/
function getEigenOperator(address _operator) external view returns (address);
}
"
},
"contracts/storage/EigenOperatorStorageUtils.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
import { IEigenOperator } from "../interfaces/IEigenOperator.sol";
/// @title EigenOperator Storage Utils
/// @author weso, Cap Labs
/// @notice Storage utilities for EigenOperator
abstract contract EigenOperatorStorageUtils {
/// @dev keccak256(abi.encode(uint256(keccak256("cap.storage.EigenOperator")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant EigenOperatorStorageLocation =
0x960b4b43d7da1001f900c7ba4e78a0a350e1c730ee58306f13b7c137edf1ee00;
/// @dev Get EigenOperator storage
/// @return $ Storage pointer
function getEigenOperatorStorage() internal pure returns (IEigenOperator.EigenOperatorStorage storage $) {
assembly {
$.slot := EigenOperatorStorageLocation
}
}
}
"
},
"contracts/delegation/providers/eigenlayer/interfaces/IAllocationManager.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
interface IAllocationManager {
/**
* @notice Struct containing parameters to slashing
* @param operator the address to slash
* @param operatorSetId the ID of the operatorSet the operator is being slashed on behalf of
* @param strategies the set of strategies to slash
* @param wadsToSlash the parts in 1e18 to slash, this will be proportional to the operator's
* slashable stake allocation for the operatorSet
* @param description the description of the slashing provided by the AVS for legibility
*/
struct SlashingParams {
address operator;
uint32 operatorSetId;
address[] strategies;
uint256[] wadsToSlash;
string description;
}
/**
* @notice Parameters used by an AVS to create new operator sets
* @param operatorSetId the id of the operator set to create
* @param strategies the strategies to add as slashable to the operator set
*/
struct CreateSetParams {
uint32 operatorSetId;
address[] strategies;
}
/**
* @notice An operator set identified by the AVS address and an identifier
* @param avs The address of the AVS this operator set belongs to
* @param id The unique identifier for the operator set
*/
struct OperatorSet {
address avs;
uint32 id;
}
/**
* @notice Called by an AVS to slash an operator in a given operator set. The operator must be registered
* and have slashable stake allocated to the operator set.
*
* @param avs The AVS address initiating the slash.
* @param params The slashing parameters, containing:
* - operator: The operator to slash.
* - operatorSetId: The ID of the operator set the operator is being slashed from.
* - strategies: Array of strategies to slash allocations from (must be in ascending order).
* - wadsToSlash: Array of proportions to slash from each strategy (must be between 0 and 1e18).
* - description: Description of why the operator was slashed.
*
* @return slashId The ID of the slash.
* @return shares The amount of shares that were slashed for each strategy.
*
* @dev For each strategy:
* 1. Reduces the operator's current allocation magnitude by wadToSlash proportion.
* 2. Reduces the strategy's max and encumbered magnitudes proportionally.
* 3. If there is a pending deallocation, reduces it proportionally.
* 4. Updates the operator's shares in the DelegationManager.
*
* @dev Small slashing amounts may not result in actual token burns due to
* rounding, which will result in small amounts of tokens locked in the contract
* rather than fully burning through the burn mechanism.
*/
function slashOperator(address avs, SlashingParams calldata params)
external
returns (uint256 slashId, uint256[] memory shares);
/**
* @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.
*
* @dev Note that the `metadataURI` is *never stored* and is only emitted in the `AVSMetadataURIUpdated` event.
*/
function updateAVSMetadataURI(address avs, string calldata metadataURI) external;
/**
* @notice Allows an AVS to create new operator sets, defining strategies that the operator set uses
*/
function createOperatorSets(address avs, CreateSetParams[] calldata params) external;
/**
* @notice Returns the minimum amount of stake that will be slashable as of some future block,
* according to each operator's allocation from each strategy to the operator set. Note that this function
* will return 0 for the slashable stake if the operator is not slashable at the time of the call.
* @dev This method queries actual delegated stakes in the DelegationManager and applies
* each operator's allocation to the stake to produce the slashable stake each allocation
* represents. This method does not consider slashable stake in the withdrawal queue even though there could be
* slashable stake in the queue.
* @dev This minimum takes into account `futureBlock`, and will omit any pending magnitude
* diffs that will not be in effect as of `futureBlock`. NOTE that in order to get the true
* minimum slashable stake as of some future block, `futureBlock` MUST be greater than block.number
* @dev NOTE that `futureBlock` should be fewer than `DEALLOCATION_DELAY` blocks in the future,
* or the values returned from this method may not be accurate due to deallocations.
* @param operatorSet the operator set to query
* @param operators the list of operators whose slashable stakes will be returned
* @param strategies the strategies that each slashable stake corresponds to
* @param futureBlock the block at which to get allocation information. Should be a future block.
*/
function getMinimumSlashableStake(
OperatorSet memory operatorSet,
address[] memory operators,
address[] memory strategies,
uint32 futureBlock
) external view returns (uint256[][] memory slashableStake);
/**
* @notice Returns the address where slashed funds will be sent for a given operator set.
* @param operatorSet The Operator Set to query.
* @return For redistributing Operator Sets, returns the configured redistribution address set during Operator Set creation.
* For non-redistributing operator sets, returns the `DEFAULT_BURN_ADDRESS`.
*/
function getRedistributionRecipient(OperatorSet memory operatorSet) external view returns (address);
/**
* @notice Adds strategies to an operator set.
* @param avs The AVS address initiating the addition.
* @param operatorSetId The ID of the operator set to which strategies are being added.
* @param strategies The strategies to add to the operator set.
*/
function addStrategiesToOperatorSet(address avs, uint32 operatorSetId, address[] calldata strategies) external;
/**
* @notice Allows an AVS to create new operator sets, defining strategies that the operator set uses
*/
function createRedistributingOperatorSets(
address avs,
CreateSetParams[] calldata params,
address[] calldata redistributionRecipients
) external;
/**
* @notice Returns the maximum magnitude of a given operator and strategy.
* @param operator The operator address.
* @param strategy The strategy address.
* @return The maximum magnitude of the operator and strategy.
*/
function getMaxMagnitude(address operator, address strategy) external view returns (uint64);
/**
* @notice Returns the allocatable magnitude of a given operator and strategy.
* @param operator The operator address.
* @param strategy The strategy address.
* @return The allocatable magnitude of the operator and strategy.
*/
function getAllocatableMagnitude(address operator, address strategy) external view returns (uint64);
/**
* @notice Parameters used to register for an AVS's operator sets
* @param avs the AVS being registered for
* @param operatorSetIds the operator sets within the AVS to register for
* @param data extra data to be passed to the AVS to complete registration
*/
struct RegisterParams {
address avs;
uint32[] operatorSetIds;
bytes data;
}
/**
* @notice Allows an operator to register for an operator set.
* @param operator The operator address.
* @param params The register parameters, containing:
* - avs: The AVS being registered for.
* - operatorSetIds: The operator sets within the AVS to register for.
* - data: Extra data to be passed to the AVS to complete registration.
*/
function registerForOperatorSets(address operator, RegisterParams calldata params) external;
/**
* @notice struct used to modify the allocation of slashable magnitude to an operator set
* @param operatorSet the operator set to modify the allocation for
* @param strategies the strategies to modify allocations for
* @param newMagnitudes the new magnitude to allocate for each strategy to this operator set
*/
struct AllocateParams {
OperatorSet operatorSet;
address[] strategies;
uint64[] newMagnitudes;
}
/**
* @notice Modifies the proportions of slashable stake allocated to an operator set from a list of strategies
* Note that deallocations remain slashable for DEALLOCATION_DELAY blocks therefore when they are cleared they may
* free up less allocatable magnitude than initially deallocated.
* @param operator the operator to modify allocations for
* @param params array of magnitude adjustments for one or more operator sets
* @dev Updates encumberedMagnitude for the updated strategies
*/
function modifyAllocations(address operator, AllocateParams[] calldata params) external;
/**
* @notice Defines allocation information from a strategy to an operator set, for an operator
* @param currentMagnitude the current magnitude allocated from the strategy to the operator set
* @param pendingDiff a pending change in magnitude, if it exists (0 otherwise)
* @param effectBlock the block at which the pending magnitude diff will take effect
*/
struct Allocation {
uint64 currentMagnitude;
int128 pendingDiff;
uint32 effectBlock;
}
/**
* @notice Returns the allocation information from a strategy to an operator set, for an operator
* @param operator the operator to get the allocation information for
* @param strategy the strategy to get the allocation information for
* @return operatorSet the operator set to which the strategy is allocated
* @return allocation the allocation information
*/
function getStrategyAllocations(address operator, address strategy)
external
view
returns (OperatorSet[] memory, Allocation[] memory);
}
"
},
"contracts/delegation/providers/eigenlayer/interfaces/IDelegationManager.sol": {
"content": " // SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
interface IDelegationManager {
/// @notice Struct that bundles together a signature and an expiration time for the signature.
/// @dev Used primarily for stack management.
struct SignatureWithExpiry {
// the signature itself, formatted as a single bytes object
bytes signature;
// the expiration timestamp (UTC) of the signature
uint256 expiry;
}
/**
* @param strategies The strategies to withdraw from
* @param depositShares For each strategy, the number of deposit shares to withdraw. Deposit shares can
* be queried via `getDepositedShares`.
* NOTE: The number of shares ultimately received when a withdrawal is completed may be lower depositShares
* if the staker or their delegated operator has experienced slashing.
* @param __deprecated_withdrawer This field is ignored. The only party that may complete a withdrawal
* is the staker that originally queued it. Alternate withdrawers are not supported.
*/
struct QueuedWithdrawalParams {
address[] strategies;
uint256[] depositShares;
address __deprecated_withdrawer;
}
/**
* @dev A struct representing an existing queued withdrawal. After the withdrawal delay has elapsed, this withdrawal can be completed via `completeQueuedWithdrawal`.
* A `Withdrawal` is created by the `DelegationManager` when `queueWithdrawals` is called. The `withdrawalRoots` hashes returned by `queueWithdrawals` can be used
* to fetch the corresponding `Withdrawal` from storage (via `getQueuedWithdrawal`).
*
* @param staker The address that queued the withdrawal
* @param delegatedTo The address that the staker was delegated to at the time the withdrawal was queued. Used to determine if additional slashing occurred before
* this withdrawal became completable.
* @param withdrawer The address that will call the contract to complete the withdrawal. Note that this will always equal `staker`; alternate withdrawers are not
* supported at this time.
* @param nonce The staker's `cumulativeWithdrawalsQueued` at time of queuing. Used to ensure withdrawals have unique hashes.
* @param startBlock The block number when the withdrawal was queued.
* @param strategies The strategies requested for withdrawal when the withdrawal was queued
* @param scaledShares The staker's deposit shares requested for withdrawal, scaled by the staker's `depositScalingFactor`. Upon completion, these will be
* scaled by the appropriate slashing factor as of the withdrawal's completable block. The result is what is actually withdrawable.
*/
struct Withdrawal {
address staker;
address delegatedTo;
address withdrawer;
uint256 nonce;
uint32 startBlock;
address[] strategies;
uint256[] scaledShares;
}
/// @notice Get the slashable shares in queue for a given operator and strategy
/// @param operator The operator address
/// @param strategy The strategy address
/// @return The slashable shares in queue
function getSlashableSharesInQueue(address operator, address strategy) external view returns (uint256);
/// @notice Get the operator shares for a given operator and strategies
/// @param operator The operator address
/// @param strategies The strategies
/// @return The operator shares
function getOperatorShares(address operator, address[] memory strategies)
external
view
returns (uint256[] memory);
/**
* @notice Returns the number of shares in storage for a staker and all their strategies
*/
function getDepositedShares(address staker) external view returns (address[] memory, uint256[] memory);
function queueWithdrawals(QueuedWithdrawalParams[] calldata params)
external
returns (bytes32[] memory withdrawalRoots);
/**
* @notice Used to complete a queued withdrawal
* @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.
* @param tokens For each `withdrawal.strategies`, the underlying token of the strategy
* NOTE: if `receiveAsTokens` is false, the `tokens` array is unused and can be filled with default values. However, `tokens.length` MUST still be equal to `withdrawal.strategies.length`.
* NOTE: For the `beaconChainETHStrategy`, the corresponding `tokens` value is ignored (can be 0).
* @param receiveAsTokens If true, withdrawn shares will be converted to tokens and sent to the caller. If false, the caller receives shares that can be delegated to an operator.
* NOTE: if the caller receives shares and is currently delegated to an operator, the received shares are
* automatically delegated to the caller's current operator.
*/
function completeQueuedWithdrawal(Withdrawal calldata withdrawal, address[] calldata tokens, bool receiveAsTokens)
external;
/**
* @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 (optional) Verifies the operator approves of this delegation
* @param approverSalt (optional) A unique single use value tied to an individual signature.
* @dev The signature/salt are used ONLY if the operator has configured a delegationApprover.
* If they have not, these params can be left empty.
*/
function delegateTo(address operator, SignatureWithExpiry memory approverSignatureAndExpiry, bytes32 approverSalt)
external;
/**
* @notice Undelegates the staker from their operator and queues a withdrawal for all of their shares
* @param staker The account to be undelegated
* @return withdrawalRoots The roots of the newly queued withdrawals, if a withdrawal was queued. Returns
* an empty array if none was queued.
*
* @dev Reverts if the `staker` is also an operator, since operators are not allowed to undelegate from themselves.
* @dev Reverts if the caller is not the staker, nor the operator who the staker is delegated to, nor the operator's specified "delegationApprover"
* @dev Reverts if the `staker` is not delegated to an operator
*/
function undelegate(address staker) external returns (bytes32[] memory withdrawalRoots);
/**
* @notice Register as an operator
* @param initDelegationApprover The initial delegation approver
* @param allocationDelay The allocation delay
* @param metadataURI The metadata URI
*/
function registerAsOperator(address initDelegationApprover, uint32 allocationDelay, string calldata metadataURI)
external;
function isOperator(address operator) external view returns (bool);
function isDelegated(address staker) external view returns (bool);
function delegationApprover(address operator) external view returns (address);
/**
* @notice Called by an operator to emit an `OperatorMetadataURIUpdated` event indicating the information has updated.
* @param operator The operator to update metadata for
* @param metadataURI The URI for metadata associated with an operator
* @dev Note that the `metadataURI` is *never stored * and is only emitted in the `OperatorMetadataURIUpdated` event
*/
function updateOperatorMetadataURI(address operator, string calldata metadataURI) external;
function calculateDelegationApprovalDigestHash(
address staker,
address operator,
address approver,
bytes32 approverSalt,
uint256 expiry
) external view returns (bytes32);
}
"
},
"contracts/delegation/providers/eigenlayer/interfaces/IRewardsCoordinator.sol": {
"content": " // SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
interface IRewardsCoordinator {
/**
* @notice An operator set identified by the AVS address and an identifier
* @param avs The address of the AVS this operator set belongs to
* @param id The unique identifier for the operator set
*/
struct OperatorSet {
address avs;
uint32 id;
}
/**
* @notice A linear combination of strategies and multipliers for AVSs to weigh
* EigenLayer strategies.
* @param strategy The EigenLayer strategy to be used for the rewards submission
* @param multiplier The weight of the strategy in the rewards submission
*/
struct StrategyAndMultiplier {
address strategy;
uint96 multiplier;
}
/**
* Sliding Window for valid RewardsSubmission startTimestamp
*
* Scenario A: GENESIS_REWARDS_TIMESTAMP IS WITHIN RANGE
* <-----MAX_RETROACTIVE_LENGTH-----> t (block.timestamp) <---MAX_FUTURE_LENGTH--->
* <--------------------valid range for startTimestamp------------------------>
* ^
* GENESIS_REWARDS_TIMESTAMP
*
*
* Scenario B: GENESIS_REWARDS_TIMESTAMP IS OUT OF RANGE
* <-----MAX_RETROACTIVE_LENGTH-----> t (block.timestamp) <---MAX_FUTURE_LENGTH--->
* <------------------------valid range for startTimestamp------------------------>
* ^
* GENESIS_REWARDS_TIMESTAMP
* @notice RewardsSubmission struct submitted by AVSs when making rewards for their operators and stakers
* RewardsSubmission can be for a time range within the valid window for startTimestamp and must be within max duration.
* See `createAVSRewardsSubmission()` for more details.
* @param strategiesAndMultipliers The strategies and their relative weights
* cannot have duplicate strategies and need to be sorted in ascending address order
* @param token The rewards token to be distributed
* @param amount The total amount of tokens to be distributed
* @param startTimestamp The timestamp (seconds) at which the submission range is considered for distribution
* could start in the past or in the future but within a valid range. See the diagram above.
* @param duration The duration of the submission range in seconds. Must be <= MAX_REWARDS_DURATION
*/
struct RewardsSubmission {
StrategyAndMultiplier[] strategiesAndMultipliers;
address token;
uint256 amount;
uint32 startTimestamp;
uint32 duration;
}
/**
* @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 duration of the `rewardsSubmission` cannot be 0 and must be a multiple of `CALCULATION_INTERVAL_SECONDS`
* @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
*/
function createAVSRewardsSubmission(RewardsSubmission[] calldata rewardsSubmissions) external;
/**
* @notice Sets the split for a specific operator for a specific avs
* @param operator The operator who is setting the split
* @param avs The avs for which the split is being set by the operator
* @param split The split for the operator for the specific avs in bips.
* @dev Only callable by the operator
* @dev Split has to be between 0 and 10000 bips (inclusive)
* @dev The split will be activated after the activation delay
*/
function setOperatorAVSSplit(address operator, address avs, uint16 split) external;
function CALCULATION_INTERVAL_SECONDS() external pure returns (uint256);
/**
* @notice A reward struct for an operator
* @param operator The operator to be rewarded
* @param amount The reward amount for the operator
*/
struct OperatorReward {
address operator;
uint256 amount;
}
/**
* @notice OperatorDirectedRewardsSubmission struct submitted by AVSs when making operator-directed rewards for their operators and stakers.
* @param strategiesAndMultipliers The strategies and their relative weights.
* @param token The rewards token to be distributed.
* @param operatorRewards The rewards for the operators.
* @param startTimestamp The timestamp (seconds) at which the submission range is considered for distribution.
* @param duration The duration of the submission range in seconds.
* @param description Describes what the rewards submission is for.
*/
struct OperatorDirectedRewardsSubmission {
StrategyAndMultiplier[] strategiesAndMultipliers;
address token;
OperatorReward[] operatorRewards;
uint32 startTimestamp;
uint32 duration;
string description;
}
function createOperatorDirectedOperatorSetRewardsSubmission(
OperatorSet calldata operatorSet,
OperatorDirectedRewardsSubmission[] calldata operatorDirectedRewardsSubmissions
) external;
function MAX_REWARDS_DURATION() external pure returns (uint32);
function activationDelay() external pure returns (uint256);
}
"
},
"node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reinitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
*
* NOTE: Consider following the ERC-7201 formula to derive storage locations.
*/
function _initializableStorageSlot() internal pure virtual returns (bytes32) {
return INITIALIZABLE_STORAGE;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
bytes32 slot = _initializableStorageSlot();
assembly {
$.slot := slot
}
}
}
"
},
"node_modules/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/UpgradeableBeacon.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "./IBeacon.sol";
import {Ownable} from "../../access/Ownable.sol";
/**
* @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their
* implementation contract, which is where they will delegate all function calls.
*
* An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.
*/
contract UpgradeableBeacon is IBeacon, Ownable {
address private _implementation;
/**
* @dev The `implementation` of the beacon is invalid.
*/
error BeaconInvalidImplementation(address implementation);
/**
* @dev Emitted when the implementation returned by the beacon is changed.
*/
event Upgraded(address indexed implementation);
/**
* @dev Sets the address of the initial implementation, and the initial owner who can upgrade the beacon.
*/
constructor(address implementation_, address initialOwner) Ownable(initialOwner) {
_setImplementation(implementation_);
}
/**
* @dev Returns the current implementation address.
*/
function implementation() public view virtual returns (address) {
return _implementation;
}
/**
* @dev Upgrades the beacon to a new implementation.
*
* Emits an {Upgraded} event.
*
* Requirements:
*
* - msg.sender must be the owner of the contract.
* - `newImplementation` must be a contract.
*/
function upgradeTo(address newImplementation) public virtual onlyOwner {
_setImplementation(newImplementation);
}
/**
* @dev Sets the implementation contract address for this beacon
*
* Requirements:
*
* - `newImplementation` must be a contract.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert BeaconInvalidImplementation(newImplementation);
}
_implementation = newImplementation;
emit Upgraded(newImplementation);
}
}
"
},
"node_modules/eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;
import "openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IStrategy.sol";
/**
* @title Interface for the `IRewardsCoordinator` contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Allows AVSs to make "Rewards Submissions", which get distributed amongst the AVSs' confirmed
* Operators and the Stakers delegated to those Operators.
* Calculations are performed based on the completed RewardsSubmission, with the results posted in
* a Merkle root against which Stakers & Operators can make claims.
*/
interface IRewardsCoordinator {
/// STRUCTS ///
/**
* @notice A linear combination of strategies and multipliers for AVSs to weigh
* EigenLayer strategies.
* @param strategy The EigenLayer strategy to be used for the rewards submission
* @param multiplier The weight of the strategy in the rewards submission
*/
struct StrategyAndMultiplier {
IStrategy strategy;
uint96 multiplier;
}
/**
* Sliding Window for valid RewardsSubmission startTimestamp
*
* Scenario A: GENESIS_REWARDS_TIMESTAMP IS WITHIN RANGE
* <-----MAX_RETROACTIVE_LENGTH-----> t (block.timestamp) <---MAX_FUTURE_LENGTH--->
* <--------------------valid range for startTimestamp------------------------>
* ^
* GENESIS_REWARDS_TIMESTAMP
*
*
* Scenario B: GENESIS_REWARDS_TIMESTAMP IS OUT OF RANGE
* <-----MAX_RETROACTIVE_LENGTH-----> t (block.timestamp) <---MAX_FUTURE_LENGTH--->
* <------------------------valid range for startTimestamp------------------------>
* ^
* GENESIS_REWARDS_TIMESTAMP
* @notice RewardsSubmission struct submitted by AVSs when making rewards for their operators and stakers
* RewardsSubmission can be for a time range within the valid window for startTimestamp and must be within max duration.
* See `createAVSRewardsSubmission()` for more details.
* @param strategiesAndMultipliers The strategies and their relative weights
* cannot have duplicate strategies and need to be sorted in ascending address order
* @param token The rewards token to be distributed
* @param amount The total amount of tokens to be distributed
* @param startTimestamp The timestamp (seconds) at which the submission range is considered for distribution
* could start in the past or in the future but within a valid range. See the diagram above.
* @param duration The duration of the submission range in seconds. Must be <= MAX_REWARDS_DURATION
*/
struct RewardsSubmission {
StrategyAndMultiplier[] strategiesAndMultipliers;
IERC20 token;
uint256 amount;
uint32 startTimestamp;
uint32 duration;
}
/**
* @notice A distribution root is a merkle root of the distribution of earnings for a given period.
* The RewardsCoordinator stores all historical distribution roots so that earners can claim their earnings against older roots
* if they wish but the merkle tree contains the cumulative earnings of all earners and tokens for a given period so earners (or their claimers if set)
* only need to claim against the latest root to claim all available earnings.
* @param root The merkle root of the distribution
* @param rewardsCalculationEndTimestamp The timestamp (seconds) until which rewards have been calculated
* @param activatedAt The timestamp (seconds) at which the root can be claimed against
*/
struct DistributionRoot {
bytes32 root;
uint32 rewardsCalculationEndTimestamp;
uint32 activatedAt;
bool disabled;
}
/**
* @notice Internal leaf in the merkle tree for the earner's account leaf
* @param earner The address of the earner
* @param earnerTokenRoot The merkle root of the earner's token subtree
* Each leaf in the earner's token subtree is a TokenTreeMerkleLeaf
*/
struct EarnerTreeMerkleLeaf {
address earner;
bytes32 earnerTokenRoot;
}
/**
* @notice The actual leaves in the distribution merkle tree specifying the token earnings
* for the respective earner's subtree. Each leaf is a claimable amount of a token for an earner.
* @param token The token for which th
Submitted on: 2025-10-21 16:07:42
Comments
Log in to comment.
No comments yet.