EigenServiceManager

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/EigenServiceManager.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;

import { Access } from "../../../access/Access.sol";
import { IEigenServiceManager } from "../../../interfaces/IEigenServiceManager.sol";
import { IOracle } from "../../../interfaces/IOracle.sol";
import { EigenServiceManagerStorageUtils } from "../../../storage/EigenServiceManagerStorageUtils.sol";
import { EigenOperator, IEigenOperator } from "./EigenOperator.sol";
import { IAllocationManager } from "./interfaces/IAllocationManager.sol";
import { IDelegationManager } from "./interfaces/IDelegationManager.sol";
import { IRewardsCoordinator } from "./interfaces/IRewardsCoordinator.sol";
import { IStrategy } from "./interfaces/IStrategy.sol";
import { IStrategyManager } from "./interfaces/IStrategyManager.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { BeaconProxy } from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
import { UpgradeableBeacon } from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { IERC20, SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

/// @title EigenServiceManager
/// @author weso, Cap Labs
/// @notice This contract acts as the avs in the eigenlayer protocol
contract EigenServiceManager is IEigenServiceManager, UUPSUpgradeable, Access, EigenServiceManagerStorageUtils {
    using SafeERC20 for IERC20;

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    /// @inheritdoc IEigenServiceManager
    function initialize(
        address _accessControl,
        EigenAddresses memory _eigenAddresses,
        address _oracle,
        uint32 _epochsBetweenDistributions
    ) external initializer {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        __Access_init(_accessControl);
        __UUPSUpgradeable_init();
        $.eigen = _eigenAddresses;
        $.oracle = _oracle;
        $.epochsBetweenDistributions = _epochsBetweenDistributions;
        $.nextOperatorId++;
        $.redistributionRecipients.push(address(this));

        // Deploy a instance for the upgradeable beacon proxies
        UpgradeableBeacon beacon = new UpgradeableBeacon(address(new EigenOperator()), address(this));
        $.eigenOperatorInstance = address(beacon);

        // Starting metadata for the avs, can be updated later and should be updated when adding new operators
        string memory metadata = "https://cap.app/meta/eigen-avs.json";

        _updateAVSMetadataURI(metadata);
    }

    /// @inheritdoc IEigenServiceManager
    function slash(address _operator, address _recipient, uint256 _slashShare, uint48)
        external
        checkAccess(this.slash.selector)
    {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        CachedOperatorData storage operatorData = $.operators[_operator];
        if (operatorData.strategy == address(0)) revert ZeroAddress();
        if (_recipient == address(0)) revert ZeroAddress();
        if (_slashShare == 0) revert ZeroSlash();

        address _strategy = operatorData.strategy;
        IERC20 _slashedCollateral = IStrategy(_strategy).underlyingToken();

        /// Slash share is a percentage of total operators collateral, this is calculated in Delegation.sol
        uint256 beforeSlash = _slashedCollateral.balanceOf(address(this));

        /// We map to the eigen operator address in this _slash function
        /// @dev rounding considerations suggested via eigen
        /// https://docs.eigencloud.xyz/products/eigenlayer/developers/howto/build/slashing/precision-rounding-considerations
        /// Since we control the magnitude and are the only allocation, rounding is less of a concern
        _slash(_strategy, _operator, _slashShare);

        /// Send slashed collateral to the liquidator
        uint256 slashedAmount = _slashedCollateral.balanceOf(address(this)) - beforeSlash;
        if (slashedAmount == 0) revert ZeroSlash();
        _slashedCollateral.safeTransfer(_recipient, slashedAmount);

        emit Slash(_operator, _recipient, slashedAmount, uint48(block.timestamp));
    }

    /// @inheritdoc IEigenServiceManager
    function distributeRewards(address _operator, address _token)
        external
        checkAccess(this.distributeRewards.selector)
    {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        CachedOperatorData storage operatorData = $.operators[_operator];

        uint256 calcIntervalSeconds = IRewardsCoordinator($.eigen.rewardsCoordinator).CALCULATION_INTERVAL_SECONDS();
        uint32 lastDistroEpoch = operatorData.lastDistributionEpoch[_token];

        /// Fetch the strategy for the operator
        address _strategy = operatorData.strategy;

        /// Check if rewards are ready - calculate available amount correctly
        uint256 _amount = IERC20(_token).balanceOf(address(this)) - $.pendingRewardsByToken[_token];

        /// If this is the first distribution, use operator creation epoch
        if (lastDistroEpoch == 0) lastDistroEpoch = operatorData.createdAtEpoch;

        /// Calculate the current epoch and check if enough time has passed
        uint32 currentEpoch = uint32(block.timestamp / calcIntervalSeconds);
        uint32 nextAllowedEpoch = lastDistroEpoch + $.epochsBetweenDistributions;

        /// If not enough time has passed since last distribution, add to pending rewards
        if (currentEpoch < nextAllowedEpoch) {
            /// Only add to pending if there are new tokens available
            if (_amount > 0) {
                $.pendingRewardsByToken[_token] += _amount;
                operatorData.pendingRewards[_token] += _amount;
            }
            return;
        }

        /// Include both new tokens and any existing pending rewards for this operator
        uint256 totalAmount = _amount + operatorData.pendingRewards[_token];

        /// Only proceed if there are rewards to distribute
        if (totalAmount == 0) return;

        _checkApproval(_token, $.eigen.rewardsCoordinator);
        _createRewardsSubmission(_operator, _strategy, _token, totalAmount, lastDistroEpoch, currentEpoch);

        /// Update accounting: subtract the pending rewards that were just distributed
        $.pendingRewardsByToken[_token] -= operatorData.pendingRewards[_token];
        operatorData.pendingRewards[_token] = 0;
        operatorData.lastDistributionEpoch[_token] = currentEpoch;

        emit DistributedRewards(_operator, _token, totalAmount);
    }

    /// @inheritdoc IEigenServiceManager
    function registerOperator(address _eigenOperator, address _avs, uint32[] calldata _operatorSetIds, bytes calldata)
        external
        checkAccess(this.registerOperator.selector)
    {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        if (_avs != address(this)) revert InvalidAVS();
        if (_operatorSetIds.length != 1) revert InvalidOperatorSetIds();
        if ($.eigenOperatorToOperator[_eigenOperator] == address(0)) revert OperatorDoesntExist();

        IAllocationManager allocationManager = IAllocationManager($.eigen.allocationManager);
        IAllocationManager.OperatorSet memory operatorSet =
            IAllocationManager.OperatorSet({ avs: _avs, id: _operatorSetIds[0] });

        address redistributionRecipient = allocationManager.getRedistributionRecipient(operatorSet);
        if (redistributionRecipient != address(this)) revert InvalidRedistributionRecipient();

        emit OperatorRegistered(IEigenOperator(_eigenOperator).operator(), _eigenOperator, _avs, _operatorSetIds[0]);
    }

    /// @inheritdoc IEigenServiceManager
    function registerStrategy(address _strategy, address _operator, address _restaker, string memory _operatorMetadata)
        external
        checkAccess(this.registerStrategy.selector)
        returns (uint32 _operatorSetId)
    {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        CachedOperatorData storage operatorData = $.operators[_operator];

        // Deploy the operator clone that will act as the operator in the eigen system
        address eigenOperator = _deployEigenOperator(_operator, _operatorMetadata);
        operatorData.eigenOperator = eigenOperator;
        _operatorSetId = $.nextOperatorId;
        $.eigenOperatorToOperator[eigenOperator] = _operator;

        // Checks, no duplicate operators or operator set ids, a strategy can have many operators.
        // Since restakers can only delegate to one operator, this is not a problem.
        // https://docs.eigencloud.xyz/products/eigenlayer/restakers/restaking-guides/restaking-developer-guide#smart-contract-delegation-user-guide
        if (operatorData.strategy != address(0)) revert AlreadyRegisteredOperator();
        if (operatorData.operatorSetId != 0) revert OperatorSetAlreadyCreated();
        if (IERC20Metadata(address(IStrategy(_strategy).underlyingToken())).decimals() < 6) revert InvalidDecimals();

        IAllocationManager allocationManager = IAllocationManager($.eigen.allocationManager);

        // Create the operator set params
        IAllocationManager.CreateSetParams[] memory params = new IAllocationManager.CreateSetParams[](1);
        address[] memory strategies = new address[](1);
        strategies[0] = _strategy;

        params[0] = IAllocationManager.CreateSetParams({ operatorSetId: _operatorSetId, strategies: strategies });

        // Create the operator set
        allocationManager.createRedistributingOperatorSets(address(this), params, $.redistributionRecipients);
        operatorData.strategy = _strategy;
        operatorData.operatorSetId = _operatorSetId;

        uint256 calcIntervalSeconds = IRewardsCoordinator($.eigen.rewardsCoordinator).CALCULATION_INTERVAL_SECONDS();
        uint256 activationDelay = IRewardsCoordinator($.eigen.rewardsCoordinator).activationDelay();
        operatorData.createdAtEpoch = uint32((block.timestamp + activationDelay) / calcIntervalSeconds);

        // Callback the operator beacon and register to the operator set
        EigenOperator(eigenOperator).registerOperatorSetToServiceManager(_operatorSetId, _restaker);

        // Increment the next operator id for the next operator set
        $.nextOperatorId++;
        emit StrategyRegistered(_strategy, _operator);
    }

    /// @inheritdoc IEigenServiceManager
    function updateAVSMetadataURI(string calldata _metadataURI)
        external
        checkAccess(this.updateAVSMetadataURI.selector)
    {
        _updateAVSMetadataURI(_metadataURI);
    }

    /// @inheritdoc IEigenServiceManager
    function setEpochsBetweenDistributions(uint32 _epochsBetweenDistributions)
        external
        checkAccess(this.setEpochsBetweenDistributions.selector)
    {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        $.epochsBetweenDistributions = _epochsBetweenDistributions;

        emit EpochsBetweenDistributionsSet(_epochsBetweenDistributions);
    }

    /// @inheritdoc IEigenServiceManager
    function allocate(address _operator) external {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        CachedOperatorData storage operatorData = $.operators[_operator];
        if (operatorData.eigenOperator == address(0)) revert ZeroAddress();

        EigenOperator(operatorData.eigenOperator).allocate(operatorData.operatorSetId, operatorData.strategy);
    }

    /// @inheritdoc IEigenServiceManager
    function upgradeEigenOperatorImplementation(address _newImplementation)
        external
        checkAccess(this.upgradeEigenOperatorImplementation.selector)
    {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        if (_newImplementation == address(0)) revert ZeroAddress();

        UpgradeableBeacon beacon = UpgradeableBeacon($.eigenOperatorInstance);
        beacon.upgradeTo(_newImplementation);
    }

    /// @inheritdoc IEigenServiceManager
    function coverage(address _operator) external view returns (uint256 delegation) {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        CachedOperatorData storage operatorData = $.operators[_operator];
        address _strategy = operatorData.strategy;
        if (_strategy == address(0)) return 0;

        address[] memory strategies = new address[](1);
        strategies[0] = _strategy;

        /// Reject small shares for coverage because of rounding concerns
        uint256[] memory operatorShares =
            IDelegationManager($.eigen.delegationManager).getOperatorShares(operatorData.eigenOperator, strategies);
        if (operatorShares[0] < 1e9) return 0;

        address _oracle = $.oracle;
        (delegation,) = _coverageByStrategy(_operator, _strategy, _oracle);
    }

    /// @inheritdoc IEigenServiceManager
    function getEigenOperator(address _operator) external view returns (address) {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        return $.operators[_operator].eigenOperator;
    }

    /// @inheritdoc IEigenServiceManager
    function slashableCollateral(address _operator, uint48) external view returns (uint256) {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        CachedOperatorData storage operatorData = $.operators[_operator];
        if (operatorData.strategy == address(0)) return 0;
        return _slashableCollateralByStrategy(_operator, operatorData.strategy);
    }

    /// @inheritdoc IEigenServiceManager
    function operatorSetId(address _operator) external view returns (uint32) {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        CachedOperatorData storage operatorData = $.operators[_operator];
        return operatorData.operatorSetId;
    }

    /// @inheritdoc IEigenServiceManager
    function operatorToStrategy(address _operator) external view returns (address) {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        CachedOperatorData storage operatorData = $.operators[_operator];
        return operatorData.strategy;
    }

    /// @inheritdoc IEigenServiceManager
    function eigenAddresses() external view returns (EigenAddresses memory) {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        return $.eigen;
    }

    /// @inheritdoc IEigenServiceManager
    function epochsBetweenDistributions() external view returns (uint32) {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        return $.epochsBetweenDistributions;
    }

    /// @inheritdoc IEigenServiceManager
    function createdAtEpoch(address _operator) external view returns (uint32) {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        return $.operators[_operator].createdAtEpoch;
    }

    /// @inheritdoc IEigenServiceManager
    function calculationIntervalSeconds() external view returns (uint256) {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        return IRewardsCoordinator($.eigen.rewardsCoordinator).CALCULATION_INTERVAL_SECONDS();
    }

    /// @inheritdoc IEigenServiceManager
    function pendingRewards(address _operator, address _token) external view returns (uint256) {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        CachedOperatorData storage operatorData = $.operators[_operator];
        return operatorData.pendingRewards[_token];
    }

    /// @dev Deploys an eigen operator
    /// @param _operator The operator/borrower address
    /// @param _operatorMetadata The operator metadata
    /// @return _eigenOperator The eigen operator contract address
    function _deployEigenOperator(address _operator, string memory _operatorMetadata)
        private
        returns (address _eigenOperator)
    {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();

        // Best practice initialize on deployment
        bytes memory initdata =
            abi.encodeWithSelector(EigenOperator.initialize.selector, address(this), _operator, _operatorMetadata);
        _eigenOperator = address(new BeaconProxy($.eigenOperatorInstance, initdata));
    }

    /// @notice Updates the metadata URI for the AVS
    /// @param _metadataURI is the metadata URI for the AVS
    function _updateAVSMetadataURI(string memory _metadataURI) private {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        IAllocationManager($.eigen.allocationManager).updateAVSMetadataURI(address(this), _metadataURI);
    }

    /// @notice Slash the operator
    /// @param _strategy The strategy address
    /// @param _operator The operator address
    /// @param _slashShare The slash share
    function _slash(address _strategy, address _operator, uint256 _slashShare) private {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        CachedOperatorData storage operatorData = $.operators[_operator];
        address[] memory strategies = new address[](1);
        strategies[0] = _strategy;

        _slashShare += 1;
        _slashShare = _slashShare > 1e18 ? 1e18 : _slashShare;

        // @dev wads are a percentage of collateral in 1e18
        uint256[] memory wadsToSlash = new uint256[](1);
        wadsToSlash[0] = _slashShare;

        IAllocationManager.SlashingParams memory slashingParams = IAllocationManager.SlashingParams({
            operator: operatorData.eigenOperator,
            operatorSetId: operatorData.operatorSetId,
            strategies: strategies,
            wadsToSlash: wadsToSlash,
            description: "liquidation"
        });

        // @dev slash the operator
        (uint256 slashId,) = IAllocationManager($.eigen.allocationManager).slashOperator(address(this), slashingParams);

        IAllocationManager.OperatorSet memory operatorSet =
            IAllocationManager.OperatorSet({ avs: address(this), id: operatorData.operatorSetId });

        // @dev clear the burn or redistributable shares, this sends them to the service manager
        IStrategyManager($.eigen.strategyManager).clearBurnOrRedistributableSharesByStrategy(
            operatorSet, slashId, _strategy
        );
    }

    /// @notice Create a rewards submission
    /// @param _operator The operator address
    /// @param _strategy The strategy address
    /// @param _token The token address
    /// @param _amount The amount of tokens (already includes pending rewards)
    /// @param _lastDistroEpoch The last distribution epoch
    /// @param _currentEpoch The current epoch
    function _createRewardsSubmission(
        address _operator,
        address _strategy,
        address _token,
        uint256 _amount,
        uint256 _lastDistroEpoch,
        uint256 _currentEpoch
    ) private {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        CachedOperatorData storage operatorData = $.operators[_operator];

        /// Get the strategy for the operator and create the rewards submission
        IRewardsCoordinator.OperatorDirectedRewardsSubmission[] memory rewardsSubmissions =
            new IRewardsCoordinator.OperatorDirectedRewardsSubmission[](1);
        IRewardsCoordinator.StrategyAndMultiplier[] memory _strategiesAndMultipliers =
            new IRewardsCoordinator.StrategyAndMultiplier[](1);

        IRewardsCoordinator.OperatorReward[] memory _operatorRewards = new IRewardsCoordinator.OperatorReward[](1);
        _operatorRewards[0] =
            IRewardsCoordinator.OperatorReward({ operator: operatorData.eigenOperator, amount: _amount });

        IRewardsCoordinator.OperatorSet memory operatorSet =
            IRewardsCoordinator.OperatorSet({ avs: address(this), id: operatorData.operatorSetId });

        /// Since there is only 1 strategy multiplier is just 1e18 everything goes to the strategy
        _strategiesAndMultipliers[0] =
            IRewardsCoordinator.StrategyAndMultiplier({ strategy: _strategy, multiplier: 1e18 });

        uint256 calcIntervalSeconds = IRewardsCoordinator($.eigen.rewardsCoordinator).CALCULATION_INTERVAL_SECONDS();

        // Start at the next epoch to next double reward the current epoch which should have been included in the previous distribution
        _lastDistroEpoch += 1;
        uint48 maxDuration = IRewardsCoordinator($.eigen.rewardsCoordinator).MAX_REWARDS_DURATION();
        uint256 startTimestamp = _lastDistroEpoch * calcIntervalSeconds;
        uint256 duration = (_currentEpoch - _lastDistroEpoch) * calcIntervalSeconds;
        if (duration > maxDuration) duration = maxDuration;

        rewardsSubmissions[0] = IRewardsCoordinator.OperatorDirectedRewardsSubmission({
            strategiesAndMultipliers: _strategiesAndMultipliers,
            token: _token,
            operatorRewards: _operatorRewards,
            startTimestamp: uint32(startTimestamp),
            duration: uint32(duration),
            description: "interest"
        });

        IRewardsCoordinator($.eigen.rewardsCoordinator).createOperatorDirectedOperatorSetRewardsSubmission(
            operatorSet, rewardsSubmissions
        );
    }

    /// @notice Check if the token has enough allowance for the spender
    /// @param _token The token to check
    /// @param _spender The spender to check
    function _checkApproval(address _token, address _spender) private {
        if (IERC20(_token).allowance(_spender, address(this)) == 0) {
            IERC20(_token).forceApprove(_spender, type(uint256).max);
        }
    }

    /// @notice Get the slashable collateral for a given operator and strategy
    /// @param _operator The operator address
    /// @param _strategy The strategy address
    /// @return The slashable collateral
    function _slashableCollateralByStrategy(address _operator, address _strategy) private view returns (uint256) {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        address collateralAddress = address(IStrategy(_strategy).underlyingToken());
        uint8 decimals = IERC20Metadata(collateralAddress).decimals();
        (uint256 collateralPrice,) = IOracle($.oracle).getPrice(collateralAddress);

        uint256 collateral = _getSlashableStake(_operator);
        uint256 collateralValue = collateral * collateralPrice / (10 ** decimals);

        return collateralValue;
    }

    /// @notice Get the coverage for a given operator and strategy
    /// @param _operator The operator address
    /// @param _strategy The strategy address
    /// @param _oracle The oracle address
    /// @return collateralValue The collateral value
    /// @return collateral The collateral
    function _coverageByStrategy(address _operator, address _strategy, address _oracle)
        private
        view
        returns (uint256 collateralValue, uint256 collateral)
    {
        address collateralAddress = address(IStrategy(_strategy).underlyingToken());
        uint8 decimals = IERC20Metadata(collateralAddress).decimals();
        (uint256 collateralPrice,) = IOracle(_oracle).getPrice(collateralAddress);

        // @dev get the minimum slashable stake
        collateral = _minimumSlashableStake(_operator, _strategy);
        collateralValue = collateral * collateralPrice / (10 ** decimals);
    }

    /// @notice Get the slashable stake for a given operator and strategy
    /// @param _operator The operator address
    /// @return The slashable stake of the operator
    function _getSlashableStake(address _operator) private view returns (uint256) {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        CachedOperatorData storage operatorData = $.operators[_operator];

        address _strategy = operatorData.strategy;
        // Get the slashable stake for the operator/OperatorSet
        uint256 slashableStake = _minimumSlashableStake(_operator, _strategy);
        // Get the stake in queue
        uint256 stakeInQueue = _slashableStakeInQueue(operatorData.eigenOperator, _strategy);
        // Sum up the slashable stake and the stake in queue
        uint256 totalSlashableStake = slashableStake + stakeInQueue;

        return totalSlashableStake;
    }

    /// @notice Get the slashable stake in queue for withdrawal from a given operator and strategy
    /// @param _operator The operator address
    /// @param _strategy The strategy address
    /// @return The slashable stake in queue for withdrawal
    function _slashableStakeInQueue(address _operator, address _strategy) private view returns (uint256) {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        // @dev get the slashable stake in queue which are waiting to be withdrawn
        return IStrategy(_strategy).sharesToUnderlyingView(
            IDelegationManager($.eigen.delegationManager).getSlashableSharesInQueue(_operator, _strategy)
        );
    }

    /// @notice Get the minimum slashable stake for a given operator and strategy
    /// @param _operator The operator address
    /// @param _strategy The strategy address
    /// @return The minimum slashable stake
    function _minimumSlashableStake(address _operator, address _strategy) private view returns (uint256) {
        EigenServiceManagerStorage storage $ = getEigenServiceManagerStorage();
        CachedOperatorData storage operatorData = $.operators[_operator];
        IAllocationManager.OperatorSet memory operatorSet =
            IAllocationManager.OperatorSet({ avs: address(this), id: operatorData.operatorSetId });
        address[] memory operators = new address[](1);
        operators[0] = operatorData.eigenOperator;
        address[] memory strategies = new address[](1);
        strategies[0] = _strategy;

        // @dev get the minimum slashable stake at the current block
        uint256[][] memory slashableShares = IAllocationManager($.eigen.allocationManager).getMinimumSlashableStake(
            operatorSet, operators, strategies, uint32(block.number)
        );
        return IStrategy(_strategy).sharesToUnderlyingView(slashableShares[0][0]);
    }

    /// @inheritdoc UUPSUpgradeable
    function _authorizeUpgrade(address) internal override checkAccess(bytes4(0)) { }
}
"
    },
    "contracts/access/Access.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;

import { IAccess } from "../interfaces/IAccess.sol";
import { IAccessControl } from "../interfaces/IAccessControl.sol";

import { AccessStorageUtils } from "../storage/AccessStorageUtils.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

/// @title Access
/// @author kexley, Cap Labs
/// @notice Inheritable access
abstract contract Access is IAccess, Initializable, AccessStorageUtils {
    /// @dev Check caller has permissions for a function, revert if call is not allowed
    /// @param _selector Function selector
    modifier checkAccess(bytes4 _selector) {
        _checkAccess(_selector);
        _;
    }

    /// @dev Initialize the access control address
    /// @param _accessControl Access control address
    function __Access_init(address _accessControl) internal onlyInitializing {
        __Access_init_unchained(_accessControl);
    }

    /// @dev Initialize unchained
    /// @param _accessControl Access control address
    function __Access_init_unchained(address _accessControl) internal onlyInitializing {
        getAccessStorage().accessControl = _accessControl;
    }

    /// @dev Check caller has access to a function, revert overwise
    /// @param _selector Function selector
    function _checkAccess(bytes4 _selector) internal view {
        bool hasAccess =
            IAccessControl(getAccessStorage().accessControl).checkAccess(_selector, address(this), msg.sender);
        if (!hasAccess) revert AccessDenied();
    }
}
"
    },
    "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/interfaces/IOracle.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;

import { IPriceOracle } from "./IPriceOracle.sol";
import { IRateOracle } from "./IRateOracle.sol";

/// @title Oracle
/// @author kexley, Cap Labs
/// @notice Price and rate oracles are unified
interface IOracle is IPriceOracle, IRateOracle {
    /// @notice Initialize the oracle
    /// @param _accessControl Access control address
    function initialize(address _accessControl) external;
}
"
    },
    "contracts/storage/EigenServiceManagerStorageUtils.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;

import { IEigenServiceManager } from "../interfaces/IEigenServiceManager.sol";

/// @title EigenServiceManager Storage Utils
/// @author weso, Cap Labs
/// @notice Storage utilities for EigenServiceManager
abstract contract EigenServiceManagerStorageUtils {
    /// @dev keccak256(abi.encode(uint256(keccak256("cap.storage.EigenServiceManager")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant EigenServiceManagerStorageLocation =
        0x9813e4033b5f31d05a061ad9d06fb8352756b0443d3cc09baeca467c0811ef00;

    /// @dev Get EigenServiceManager storage
    /// @return $ Storage pointer
    function getEigenServiceManagerStorage()
        internal
        pure
        returns (IEigenServiceManager.EigenServiceManagerStorage storage $)
    {
        assembly {
            $.slot := EigenServiceManagerStorageLocation
        }
    }
}
"
    },
    "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/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 callda

Tags:
ERC20, ERC165, Multisig, Upgradeable, Multi-Signature, Factory, Oracle|addr:0x45b40687d3ea71686bc4c66d98ce98f71be3d63b|verified:true|block:23634683|tx:0x9f522e77d509d7c93e9ac136b4f51f95d6d0c51ac127e6797681f59c7f2d65fa|first_check:1761291792

Submitted on: 2025-10-24 09:43:14

Comments

Log in to comment.

No comments yet.