// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; import "./IInvestmentStrategy.sol"; import "./ISlasher.sol"; import "./IEigenLayrDelegation.sol"; import "./IServiceManager.sol"; /** * @title Interface for the primary entrypoint for funds into EigenLayr. * @author Layr Labs, Inc. * @notice See the `InvestmentManager` contract itself for implementation details. */ interface IInvestmentManager { // packed struct for queued withdrawals struct WithdrawerAndNonce { address withdrawer; uint96 nonce; } /** * Struct type used to specify an existing queued withdrawal. Rather than storing the entire struct, only a hash is stored. * In functions that operate on existing queued withdrawals -- e.g. `startQueuedWithdrawalWaitingPeriod` or `completeQueuedWithdrawal`, * the data is resubmitted and the hash of the submitted data is computed by `calculateWithdrawalRoot` and checked against the * stored hash in order to confirm the integrity of the submitted data. */ struct QueuedWithdrawal { IInvestmentStrategy[] strategies; IERC20[] tokens; uint256[] shares; address depositor; WithdrawerAndNonce withdrawerAndNonce; uint32 withdrawalStartBlock; address delegatedAddress; } /** * @notice Deposits `amount` of `token` into the specified `strategy`, with the resultant shares credited to `depositor` * @param strategy is the specified strategy where investment is to be made, * @param token is the denomination in which the investment is to be made, * @param amount is the amount of token to be invested in the strategy by the depositor * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf. * @dev Cannot be called by an address that is 'frozen' (this function will revert if the `msg.sender` is frozen). */ function depositIntoStrategy(IInvestmentStrategy strategy, IERC20 token, uint256 amount) external returns (uint256); /** * @notice Deposits `amount` of beaconchain ETH into this contract on behalf of `staker` * @param staker is the entity that is restaking in eigenlayer, * @param amount is the amount of beaconchain ETH being restaked, * @param amount is the amount of token to be invested in the strategy by the depositor * @dev Only callable by EigenPod for the staker. */ function depositBeaconChainETH(address staker, uint256 amount) external; /** * @notice Records an overcommitment event on behalf of a staker. This allows EigenLayer to slash the overcommitted balance. * It decreases the delegated shares, but does not freeze the `slashedAddress` completely. * @param overcommittedPodOwner is the pod owner to be slashed * @param beaconChainETHStrategyIndex is the index of the beaconChainETHStrategy in case it must be removed, * @param amount is the amount of token overcommitted to EigenLayer * @dev Only callable by EigenPod for the overcommittedPodOwner. */ function recordOvercommittedBeaconChainETH(address overcommittedPodOwner, uint256 beaconChainETHStrategyIndex, uint256 amount) external; /** * @notice Used for investing an asset into the specified strategy with the resultant shared created to `staker`, * who must sign off on the action * @param strategy is the specified strategy where investment is to be made, * @param token is the denomination in which the investment is to be made, * @param amount is the amount of token to be invested in the strategy by the depositor * @param staker the staker that the assets will be deposited on behalf of * @param expiry the timestamp at which the signature expires * @param r and @param vs are the elements of the ECDSA signature * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf. * @dev A signature is required for this function to eliminate the possibility of griefing attacks, specifically those * targetting stakers who may be attempting to undelegate. * @dev Cannot be called on behalf of a staker that is 'frozen' (this function will revert if the `staker` is frozen). */ function depositIntoStrategyOnBehalfOf( IInvestmentStrategy strategy, IERC20 token, uint256 amount, address staker, uint256 expiry, bytes32 r, bytes32 vs ) external returns (uint256 shares); /// @notice Returns the current shares of `user` in `strategy` function investorStratShares(address user, IInvestmentStrategy strategy) external view returns (uint256 shares); /** * @notice Get all details on the depositor's investments and corresponding shares * @return (depositor's strategies, shares in these strategies) */ function getDeposits(address depositor) external view returns (IInvestmentStrategy[] memory, uint256[] memory); /// @notice Simple getter function that returns `investorStrats[staker].length`. function investorStratsLength(address staker) external view returns (uint256); /** * @notice Called by a staker to queue a withdraw in the given token and shareAmount from each of the respective given strategies. * @dev Stakers will complete their withdrawal by calling the 'completeQueuedWithdrawal' function. * User shares are decreased in this function, but the total number of shares in each strategy remains the same. * The total number of shares is decremented in the 'completeQueuedWithdrawal' function instead, which is where * the funds are actually sent to the user through use of the strategies' 'withdrawal' function. This ensures * that the value per share reported by each strategy will remain consistent, and that the shares will continue * to accrue gains during the enforced WITHDRAWAL_WAITING_PERIOD. * @param strategyIndexes is a list of the indices in `investorStrats[msg.sender]` that correspond to the strategies * for which `msg.sender` is withdrawing 100% of their shares * @dev Strategies are removed from `investorStrats` by swapping the last entry with the entry to be removed, then * popping off the last entry in `investorStrats`. The simplest way to calculate the correct `strategyIndexes` to input * is to order the strategies *for which `msg.sender` is withdrawing 100% of their shares* from highest index in * `investorStrats` to lowest index * @dev Note that if the withdrawal includes shares in the enshrined 'beaconChainETH' strategy, then it must *only* include shares in this strategy, and * `withdrawer` must match the caller's address. The first condition is because slashing of queued withdrawals cannot be guaranteed * for Beacon Chain ETH (since we cannot trigger a withdrawal from the beacon chain through a smart contract) and the second condition is because shares in * the enshrined 'beaconChainETH' strategy technically represent non-fungible positions (deposits to the Beacon Chain, each pointed at a specific EigenPod). */ function queueWithdrawal( uint256[] calldata strategyIndexes, IInvestmentStrategy[] calldata strategies, IERC20[] calldata tokens, uint256[] calldata shareAmounts, address withdrawer, bool undelegateIfPossible ) external returns(bytes32); /** * @notice Used to complete the specified `queuedWithdrawal`. The function caller must match `queuedWithdrawal.withdrawer` * @param queuedWithdrawal The QueuedWithdrawal to complete. * @param middlewareTimesIndex is the index in the operator that the staker who triggered the withdrawal was delegated to's middleware times array * @param receiveAsTokens If true, the shares specified in the queued withdrawal will be withdrawn from the specified strategies themselves * and sent to the caller, through calls to `queuedWithdrawal.strategies[i].withdraw`. If false, then the shares in the specified strategies * will simply be transferred to the caller directly. * @dev middlewareTimesIndex should be calculated off chain before calling this function by finding the first index that satisfies `slasher.canWithdraw` */ function completeQueuedWithdrawal( QueuedWithdrawal calldata queuedWithdrawal, uint256 middlewareTimesIndex, bool receiveAsTokens ) external; /** * @notice Slashes the shares of a 'frozen' operator (or a staker delegated to one) * @param slashedAddress is the frozen address that is having its shares slashed * @param strategyIndexes is a list of the indices in `investorStrats[msg.sender]` that correspond to the strategies * for which `msg.sender` is withdrawing 100% of their shares * @param recipient The slashed funds are withdrawn as tokens to this address. * @dev strategies are removed from `investorStrats` by swapping the last entry with the entry to be removed, then * popping off the last entry in `investorStrats`. The simplest way to calculate the correct `strategyIndexes` to input * is to order the strategies *for which `msg.sender` is withdrawing 100% of their shares* from highest index in * `investorStrats` to lowest index */ function slashShares( address slashedAddress, address recipient, IInvestmentStrategy[] calldata strategies, IERC20[] calldata tokens, uint256[] calldata strategyIndexes, uint256[] calldata shareAmounts ) external; /** * @notice Slashes an existing queued withdrawal that was created by a 'frozen' operator (or a staker delegated to one) * @param recipient The funds in the slashed withdrawal are withdrawn as tokens to this address. */ function slashQueuedWithdrawal( address recipient, QueuedWithdrawal calldata queuedWithdrawal ) external; /// @notice Returns the keccak256 hash of `queuedWithdrawal`. function calculateWithdrawalRoot( QueuedWithdrawal memory queuedWithdrawal ) external pure returns (bytes32); /// @notice Returns the single, central Delegation contract of EigenLayer function delegation() external view returns (IEigenLayrDelegation); /// @notice Returns the single, central Slasher contract of EigenLayer function slasher() external view returns (ISlasher); /// @notice returns the enshrined beaconChainETH Strategy function beaconChainETHStrategy() external view returns (IInvestmentStrategy); }