Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 1 from a total of 1 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Change Admin | 20860346 | 527 days ago | IN | 0 ETH | 0.0004338 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
StrategyBaseTVLLimits
Compiler Version
v0.8.12+commit.f00d7308
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;
import "./StrategyBase.sol";
/**
* @title A Strategy implementation inheriting from `StrategyBase` that limits the total amount of deposits it will accept.
* @dev Note that this implementation still converts between any amount of shares or underlying tokens in its view functions;
* these functions purposefully do not take the TVL limit into account.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
*/
contract StrategyBaseTVLLimits is StrategyBase {
/// The maximum deposit (in underlyingToken) that this strategy will accept per deposit
uint256 public maxPerDeposit;
/// The maximum deposits (in underlyingToken) that this strategy will hold
uint256 public maxTotalDeposits;
/// @notice Emitted when `maxPerDeposit` value is updated from `previousValue` to `newValue`
event MaxPerDepositUpdated(uint256 previousValue, uint256 newValue);
/// @notice Emitted when `maxTotalDeposits` value is updated from `previousValue` to `newValue`
event MaxTotalDepositsUpdated(uint256 previousValue, uint256 newValue);
constructor(IStrategyManager _strategyManager) StrategyBase(_strategyManager) {}
function initialize(uint256 _maxPerDeposit, uint256 _maxTotalDeposits, IERC20 _underlyingToken, IPauserRegistry _pauserRegistry)
public virtual initializer
{
_setTVLLimits(_maxPerDeposit, _maxTotalDeposits);
_initializeStrategyBase(_underlyingToken, _pauserRegistry);
}
/**
* @notice Sets the maximum deposits (in underlyingToken) that this strategy will hold and accept per deposit
* @param newMaxTotalDeposits The new maximum deposits
* @dev Callable only by the unpauser of this contract
* @dev We note that there is a potential race condition between a call to this function that lowers either or both of these limits and call(s)
* to `deposit`, that may result in some calls to `deposit` reverting.
*/
function setTVLLimits(uint256 newMaxPerDeposit, uint256 newMaxTotalDeposits) external onlyUnpauser {
_setTVLLimits(newMaxPerDeposit, newMaxTotalDeposits);
}
/// @notice Simple getter function that returns the current values of `maxPerDeposit` and `maxTotalDeposits`.
function getTVLLimits() external view returns (uint256, uint256) {
return (maxPerDeposit, maxTotalDeposits);
}
/// @notice Internal setter for TVL limits
function _setTVLLimits(uint256 newMaxPerDeposit, uint256 newMaxTotalDeposits) internal {
emit MaxPerDepositUpdated(maxPerDeposit, newMaxPerDeposit);
emit MaxTotalDepositsUpdated(maxTotalDeposits, newMaxTotalDeposits);
require(newMaxPerDeposit <= newMaxTotalDeposits, "StrategyBaseTVLLimits._setTVLLimits: maxPerDeposit exceeds maxTotalDeposits");
maxPerDeposit = newMaxPerDeposit;
maxTotalDeposits = newMaxTotalDeposits;
}
/**
* @notice Called in the external `deposit` function, before any logic is executed. Makes sure that deposits don't exceed configured maximum.
* @dev Unused token param is the token being deposited. This is already checked in the `deposit` function.
* @dev Note that the `maxTotalDeposits` is purely checked against the current `_tokenBalance()`, since by this point in the deposit flow, the
* tokens should have already been transferred to this Strategy by the StrategyManager
* @dev We note as well that this makes it possible for various race conditions to occur:
* a) multiple simultaneous calls to `deposit` may result in some of these calls reverting due to `maxTotalDeposits` being reached.
* b) transferring funds directly to this Strategy (although not generally in someone's economic self interest) in order to reach `maxTotalDeposits`
* is a route by which someone can cause calls to `deposit` to revert.
* c) increases in the token balance of this contract through other effects – including token rebasing – may cause similar issues to (a) and (b).
* @param amount The amount of `token` being deposited
*/
function _beforeDeposit(IERC20 /*token*/, uint256 amount) internal virtual override {
require(amount <= maxPerDeposit, "StrategyBaseTVLLimits: max per deposit exceeded");
require(_tokenBalance() <= maxTotalDeposits, "StrategyBaseTVLLimits: max deposits exceeded");
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[48] private __gap;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;
import "../interfaces/IStrategyManager.sol";
import "../permissions/Pausable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
/**
* @title Base implementation of `IStrategy` interface, designed to be inherited from by more complex strategies.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Simple, basic, "do-nothing" Strategy that holds a single underlying token and returns it on withdrawals.
* Implements minimal versions of the IStrategy functions, this contract is designed to be inherited by
* more complex strategies, which can then override its functions as necessary.
* @dev Note that some functions have their mutability restricted; developers inheriting from this contract cannot broaden
* the mutability without modifying this contract itself.
* @dev This contract is expressly *not* intended for use with 'fee-on-transfer'-type tokens.
* Setting the `underlyingToken` to be a fee-on-transfer token may result in improper accounting.
* @notice This contract functions similarly to an ERC4626 vault, only without issuing a token.
* To mitigate against the common "inflation attack" vector, we have chosen to use the 'virtual shares' mitigation route,
* similar to [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/ERC4626.sol).
* We acknowledge that this mitigation has the known downside of the virtual shares causing some losses to users, which are pronounced
* particularly in the case of the share exchange rate changing signficantly, either positively or negatively.
* For a fairly thorough discussion of this issue and our chosen mitigation strategy, we recommend reading through
* [this thread](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706) on the OpenZeppelin repo.
* We specifically use a share offset of `SHARES_OFFSET` and a balance offset of `BALANCE_OFFSET`.
*/
contract StrategyBase is Initializable, Pausable, IStrategy {
using SafeERC20 for IERC20;
uint8 internal constant PAUSED_DEPOSITS = 0;
uint8 internal constant PAUSED_WITHDRAWALS = 1;
/**
* @notice virtual shares used as part of the mitigation of the common 'share inflation' attack vector.
* Constant value chosen to reasonably reduce attempted share inflation by the first depositor, while still
* incurring reasonably small losses to depositors
*/
uint256 internal constant SHARES_OFFSET = 1e3;
/**
* @notice virtual balance used as part of the mitigation of the common 'share inflation' attack vector
* Constant value chosen to reasonably reduce attempted share inflation by the first depositor, while still
* incurring reasonably small losses to depositors
*/
uint256 internal constant BALANCE_OFFSET = 1e3;
/// @notice EigenLayer's StrategyManager contract
IStrategyManager public immutable strategyManager;
/// @notice The underlying token for shares in this Strategy
IERC20 public underlyingToken;
/// @notice The total number of extant shares in this Strategy
uint256 public totalShares;
/// @notice Simply checks that the `msg.sender` is the `strategyManager`, which is an address stored immutably at construction.
modifier onlyStrategyManager() {
require(msg.sender == address(strategyManager), "StrategyBase.onlyStrategyManager");
_;
}
/// @notice Since this contract is designed to be initializable, the constructor simply sets `strategyManager`, the only immutable variable.
constructor(IStrategyManager _strategyManager) {
strategyManager = _strategyManager;
_disableInitializers();
}
function initialize(IERC20 _underlyingToken, IPauserRegistry _pauserRegistry) public virtual initializer {
_initializeStrategyBase(_underlyingToken, _pauserRegistry);
}
/// @notice Sets the `underlyingToken` and `pauserRegistry` for the strategy.
function _initializeStrategyBase(IERC20 _underlyingToken, IPauserRegistry _pauserRegistry) internal onlyInitializing {
underlyingToken = _underlyingToken;
_initializePauser(_pauserRegistry, UNPAUSE_ALL);
}
/**
* @notice Used to deposit tokens into this Strategy
* @param token is the ERC20 token being deposited
* @param amount is the amount of token being deposited
* @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
* `depositIntoStrategy` function, and individual share balances are recorded in the strategyManager as well.
* @dev Note that the assumption is made that `amount` of `token` has already been transferred directly to this contract
* (as performed in the StrategyManager's deposit functions). In particular, setting the `underlyingToken` of this contract
* to be a fee-on-transfer token will break the assumption that the amount this contract *received* of the token is equal to
* the amount that was input when the transfer was performed (i.e. the amount transferred 'out' of the depositor's balance).
* @return newShares is the number of new shares issued at the current exchange ratio.
*/
function deposit(IERC20 token, uint256 amount)
external
virtual
override
onlyWhenNotPaused(PAUSED_DEPOSITS)
onlyStrategyManager
returns (uint256 newShares)
{
// call hook to allow for any pre-deposit logic
_beforeDeposit(token, amount);
require(token == underlyingToken, "StrategyBase.deposit: Can only deposit underlyingToken");
// copy `totalShares` value to memory, prior to any change
uint256 priorTotalShares = totalShares;
/**
* @notice calculation of newShares *mirrors* `underlyingToShares(amount)`, but is different since the balance of `underlyingToken`
* has already been increased due to the `strategyManager` transferring tokens to this strategy prior to calling this function
*/
// account for virtual shares and balance
uint256 virtualShareAmount = priorTotalShares + SHARES_OFFSET;
uint256 virtualTokenBalance = _tokenBalance() + BALANCE_OFFSET;
// calculate the prior virtual balance to account for the tokens that were already transferred to this contract
uint256 virtualPriorTokenBalance = virtualTokenBalance - amount;
newShares = (amount * virtualShareAmount) / virtualPriorTokenBalance;
// extra check for correctness / against edge case where share rate can be massively inflated as a 'griefing' sort of attack
require(newShares != 0, "StrategyBase.deposit: newShares cannot be zero");
// update total share amount to account for deposit
totalShares = (priorTotalShares + newShares);
return newShares;
}
/**
* @notice Used to withdraw tokens from this Strategy, to the `depositor`'s address
* @param depositor is the address to receive the withdrawn funds
* @param token is the ERC20 token being transferred out
* @param amountShares is the amount of shares being withdrawn
* @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
* other functions, and individual share balances are recorded in the strategyManager as well.
*/
function withdraw(address depositor, IERC20 token, uint256 amountShares)
external
virtual
override
onlyWhenNotPaused(PAUSED_WITHDRAWALS)
onlyStrategyManager
{
// call hook to allow for any pre-withdrawal logic
_beforeWithdrawal(depositor, token, amountShares);
require(token == underlyingToken, "StrategyBase.withdraw: Can only withdraw the strategy token");
// copy `totalShares` value to memory, prior to any change
uint256 priorTotalShares = totalShares;
require(
amountShares <= priorTotalShares,
"StrategyBase.withdraw: amountShares must be less than or equal to totalShares"
);
/**
* @notice calculation of amountToSend *mirrors* `sharesToUnderlying(amountShares)`, but is different since the `totalShares` has already
* been decremented. Specifically, notice how we use `priorTotalShares` here instead of `totalShares`.
*/
// account for virtual shares and balance
uint256 virtualPriorTotalShares = priorTotalShares + SHARES_OFFSET;
uint256 virtualTokenBalance = _tokenBalance() + BALANCE_OFFSET;
// calculate ratio based on virtual shares and balance, being careful to multiply before dividing
uint256 amountToSend = (virtualTokenBalance * amountShares) / virtualPriorTotalShares;
// Decrease the `totalShares` value to reflect the withdrawal
totalShares = priorTotalShares - amountShares;
underlyingToken.safeTransfer(depositor, amountToSend);
}
/**
* @notice Called in the external `deposit` function, before any logic is executed. Expected to be overridden if strategies want such logic.
* @param token The token being deposited
* @param amount The amount of `token` being deposited
*/
function _beforeDeposit(IERC20 token, uint256 amount) internal virtual {}
/**
* @notice Called in the external `withdraw` function, before any logic is executed. Expected to be overridden if strategies want such logic.
* @param depositor The address that will receive the withdrawn tokens
* @param token The token being withdrawn
* @param amountShares The amount of shares being withdrawn
*/
function _beforeWithdrawal(address depositor, IERC20 token, uint256 amountShares) internal virtual {}
/**
* @notice Currently returns a brief string explaining the strategy's goal & purpose, but for more complex
* strategies, may be a link to metadata that explains in more detail.
*/
function explanation() external pure virtual override returns (string memory) {
return "Base Strategy implementation to inherit from for more complex implementations";
}
/**
* @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
* @notice In contrast to `sharesToUnderlying`, this function guarantees no state modifications
* @param amountShares is the amount of shares to calculate its conversion into the underlying token
* @return The amount of underlying tokens corresponding to the input `amountShares`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function sharesToUnderlyingView(uint256 amountShares) public view virtual override returns (uint256) {
// account for virtual shares and balance
uint256 virtualTotalShares = totalShares + SHARES_OFFSET;
uint256 virtualTokenBalance = _tokenBalance() + BALANCE_OFFSET;
// calculate ratio based on virtual shares and balance, being careful to multiply before dividing
return (virtualTokenBalance * amountShares) / virtualTotalShares;
}
/**
* @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
* @notice In contrast to `sharesToUnderlyingView`, this function **may** make state modifications
* @param amountShares is the amount of shares to calculate its conversion into the underlying token
* @return The amount of underlying tokens corresponding to the input `amountShares`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function sharesToUnderlying(uint256 amountShares) public view virtual override returns (uint256) {
return sharesToUnderlyingView(amountShares);
}
/**
* @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
* @notice In contrast to `underlyingToShares`, this function guarantees no state modifications
* @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
* @return The amount of shares corresponding to the input `amountUnderlying`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function underlyingToSharesView(uint256 amountUnderlying) public view virtual returns (uint256) {
// account for virtual shares and balance
uint256 virtualTotalShares = totalShares + SHARES_OFFSET;
uint256 virtualTokenBalance = _tokenBalance() + BALANCE_OFFSET;
// calculate ratio based on virtual shares and balance, being careful to multiply before dividing
return (amountUnderlying * virtualTotalShares) / virtualTokenBalance;
}
/**
* @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
* @notice In contrast to `underlyingToSharesView`, this function **may** make state modifications
* @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
* @return The amount of shares corresponding to the input `amountUnderlying`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function underlyingToShares(uint256 amountUnderlying) external view virtual returns (uint256) {
return underlyingToSharesView(amountUnderlying);
}
/**
* @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
* this strategy. In contrast to `userUnderlying`, this function guarantees no state modifications
*/
function userUnderlyingView(address user) external view virtual returns (uint256) {
return sharesToUnderlyingView(shares(user));
}
/**
* @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
* this strategy. In contrast to `userUnderlyingView`, this function **may** make state modifications
*/
function userUnderlying(address user) external virtual returns (uint256) {
return sharesToUnderlying(shares(user));
}
/**
* @notice convenience function for fetching the current total shares of `user` in this strategy, by
* querying the `strategyManager` contract
*/
function shares(address user) public view virtual returns (uint256) {
return strategyManager.stakerStrategyShares(user, IStrategy(address(this)));
}
/// @notice Internal function used to fetch this contract's current balance of `underlyingToken`.
// slither-disable-next-line dead-code
function _tokenBalance() internal view virtual returns (uint256) {
return underlyingToken.balanceOf(address(this));
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[48] private __gap;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;
import "./IStrategy.sol";
import "./ISlasher.sol";
import "./IDelegationManager.sol";
/**
* @title Interface for the primary entrypoint for funds into EigenLayer.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice See the `StrategyManager` contract itself for implementation details.
*/
interface IStrategyManager {
// packed struct for queued withdrawals; helps deal with stack-too-deep errors
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 {
IStrategy[] strategies;
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 `msg.sender`
* @param strategy is the specified strategy where deposit is to be made,
* @param token is the denomination in which the deposit is to be made,
* @param amount is the amount of token to be deposited in the strategy by the depositor
* @return shares The amount of new shares in the `strategy` created as part of the action.
* @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf.
* @dev Cannot be called by an address that is 'frozen' (this function will revert if the `msg.sender` is frozen).
*
* WARNING: Depositing tokens that allow reentrancy (eg. ERC-777) into a strategy is not recommended. This can lead to attack vectors
* where the token balance and corresponding strategy shares are not in sync upon reentrancy.
*/
function depositIntoStrategy(IStrategy strategy, IERC20 token, uint256 amount)
external
returns (uint256 shares);
/**
* @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,
* @dev Only callable by EigenPodManager.
*/
function depositBeaconChainETH(address staker, uint256 amount) external;
/**
* @notice Records an overcommitment event on behalf of a staker. The staker's beaconChainETH shares are decremented by `amount`.
* @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 to decrement the slashedAddress's beaconChainETHStrategy shares
* @dev Only callable by EigenPodManager.
*/
function recordOvercommittedBeaconChainETH(address overcommittedPodOwner, uint256 beaconChainETHStrategyIndex, uint256 amount)
external;
/**
* @notice Used for depositing an asset into the specified strategy with the resultant shares credited to `staker`,
* who must sign off on the action.
* Note that the assets are transferred out/from the `msg.sender`, not from the `staker`; this function is explicitly designed
* purely to help one address deposit 'for' another.
* @param strategy is the specified strategy where deposit is to be made,
* @param token is the denomination in which the deposit is to be made,
* @param amount is the amount of token to be deposited in the strategy by the depositor
* @param staker the staker that the deposited assets will be credited to
* @param expiry the timestamp at which the signature expires
* @param signature is a valid signature from the `staker`. either an ECDSA signature if the `staker` is an EOA, or data to forward
* following EIP-1271 if the `staker` is a contract
* @return shares The amount of new shares in the `strategy` created as part of the action.
* @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf.
* @dev A signature is required for this function to eliminate the possibility of griefing attacks, specifically those
* targeting stakers who may be attempting to undelegate.
* @dev Cannot be called on behalf of a staker that is 'frozen' (this function will revert if the `staker` is frozen).
*
* WARNING: Depositing tokens that allow reentrancy (eg. ERC-777) into a strategy is not recommended. This can lead to attack vectors
* where the token balance and corresponding strategy shares are not in sync upon reentrancy
*/
function depositIntoStrategyWithSignature(
IStrategy strategy,
IERC20 token,
uint256 amount,
address staker,
uint256 expiry,
bytes memory signature
)
external
returns (uint256 shares);
/// @notice Returns the current shares of `user` in `strategy`
function stakerStrategyShares(address user, IStrategy strategy) external view returns (uint256 shares);
/**
* @notice Get all details on the depositor's deposits and corresponding shares
* @return (depositor's strategies, shares in these strategies)
*/
function getDeposits(address depositor) external view returns (IStrategy[] memory, uint256[] memory);
/// @notice Simple getter function that returns `stakerStrategyList[staker].length`.
function stakerStrategyListLength(address staker) external view returns (uint256);
/**
* @notice Called by a staker to queue a withdrawal of the given amount of `shares` 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 `stakerStrategyList[msg.sender]` that correspond to the strategies
* for which `msg.sender` is withdrawing 100% of their shares
* @param strategies The Strategies to withdraw from
* @param shares The amount of shares to withdraw from each of the respective Strategies in the `strategies` array
* @param withdrawer The address that can complete the withdrawal and will receive any withdrawn funds or shares upon completing the withdrawal
* @param undelegateIfPossible If this param is marked as 'true' *and the withdrawal will result in `msg.sender` having no shares in any Strategy,*
* then this function will also make an internal call to `undelegate(msg.sender)` to undelegate the `msg.sender`.
* @return The 'withdrawalRoot' of the newly created Queued Withdrawal
* @dev Strategies are removed from `stakerStrategyList` by swapping the last entry with the entry to be removed, then
* popping off the last entry in `stakerStrategyList`. 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
* `stakerStrategyList` 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,
IStrategy[] calldata strategies,
uint256[] calldata shares,
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 tokens Array in which the i-th entry specifies the `token` input to the 'withdraw' function of the i-th Strategy in the `strategies` array
* of the `queuedWithdrawal`. This input can be provided with zero length if `receiveAsTokens` is set to 'false' (since in that case, this input will be unused)
* @param middlewareTimesIndex is the index in the operator that the staker who triggered the withdrawal was delegated to's middleware times array
* @param receiveAsTokens If true, the shares specified in the 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,
IERC20[] calldata tokens,
uint256 middlewareTimesIndex,
bool receiveAsTokens
)
external;
/**
* @notice Used to complete the specified `queuedWithdrawals`. The function caller must match `queuedWithdrawals[...].withdrawer`
* @param queuedWithdrawals The QueuedWithdrawals to complete.
* @param tokens Array of tokens for each QueuedWithdrawal. See `completeQueuedWithdrawal` for the usage of a single array.
* @param middlewareTimesIndexes One index to reference per QueuedWithdrawal. See `completeQueuedWithdrawal` for the usage of a single index.
* @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 Array-ified version of `completeQueuedWithdrawal`
* @dev middlewareTimesIndex should be calculated off chain before calling this function by finding the first index that satisfies `slasher.canWithdraw`
*/
function completeQueuedWithdrawals(
QueuedWithdrawal[] calldata queuedWithdrawals,
IERC20[][] calldata tokens,
uint256[] calldata middlewareTimesIndexes,
bool[] calldata 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 recipient is the address that will receive the slashed funds, which could e.g. be a harmed party themself,
* or a MerkleDistributor-type contract that further sub-divides the slashed funds.
* @param strategies Strategies to slash
* @param shareAmounts The amount of shares to slash in each of the provided `strategies`
* @param tokens The tokens to use as input to the `withdraw` function of each of the provided `strategies`
* @param strategyIndexes is a list of the indices in `stakerStrategyList[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 `stakerStrategyList` by swapping the last entry with the entry to be removed, then
* popping off the last entry in `stakerStrategyList`. 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
* `stakerStrategyList` to lowest index
*/
function slashShares(
address slashedAddress,
address recipient,
IStrategy[] 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.
* @param queuedWithdrawal The previously queued withdrawal to be slashed
* @param tokens Array in which the i-th entry specifies the `token` input to the 'withdraw' function of the i-th Strategy in the `strategies`
* array of the `queuedWithdrawal`.
* @param indicesToSkip Optional input parameter -- indices in the `strategies` array to skip (i.e. not call the 'withdraw' function on). This input exists
* so that, e.g., if the slashed QueuedWithdrawal contains a malicious strategy in the `strategies` array which always reverts on calls to its 'withdraw' function,
* then the malicious strategy can be skipped (with the shares in effect "burned"), while the non-malicious strategies are still called as normal.
*/
function slashQueuedWithdrawal(address recipient, QueuedWithdrawal calldata queuedWithdrawal, IERC20[] calldata tokens, uint256[] calldata indicesToSkip)
external;
/// @notice Returns the keccak256 hash of `queuedWithdrawal`.
function calculateWithdrawalRoot(
QueuedWithdrawal memory queuedWithdrawal
)
external
pure
returns (bytes32);
/**
* @notice Owner-only function that adds the provided Strategies to the 'whitelist' of strategies that stakers can deposit into
* @param strategiesToWhitelist Strategies that will be added to the `strategyIsWhitelistedForDeposit` mapping (if they aren't in it already)
*/
function addStrategiesToDepositWhitelist(IStrategy[] calldata strategiesToWhitelist) external;
/**
* @notice Owner-only function that removes the provided Strategies from the 'whitelist' of strategies that stakers can deposit into
* @param strategiesToRemoveFromWhitelist Strategies that will be removed to the `strategyIsWhitelistedForDeposit` mapping (if they are in it)
*/
function removeStrategiesFromDepositWhitelist(IStrategy[] calldata strategiesToRemoveFromWhitelist) external;
/// @notice Returns the single, central Delegation contract of EigenLayer
function delegation() external view returns (IDelegationManager);
/// @notice Returns the single, central Slasher contract of EigenLayer
function slasher() external view returns (ISlasher);
/// @notice returns the enshrined, virtual 'beaconChainETH' Strategy
function beaconChainETHStrategy() external view returns (IStrategy);
/// @notice Returns the number of blocks that must pass between the time a withdrawal is queued and the time it can be completed
function withdrawalDelayBlocks() external view returns (uint256);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;
import "../interfaces/IPausable.sol";
/**
* @title Adds pausability to a contract, with pausing & unpausing controlled by the `pauser` and `unpauser` of a PauserRegistry contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Contracts that inherit from this contract may define their own `pause` and `unpause` (and/or related) functions.
* These functions should be permissioned as "onlyPauser" which defers to a `PauserRegistry` for determining access control.
* @dev Pausability is implemented using a uint256, which allows up to 256 different single bit-flags; each bit can potentially pause different functionality.
* Inspiration for this was taken from the NearBridge design here https://etherscan.io/address/0x3FEFc5A4B1c02f21cBc8D3613643ba0635b9a873#code.
* For the `pause` and `unpause` functions we've implemented, if you pause, you can only flip (any number of) switches to on/1 (aka "paused"), and if you unpause,
* you can only flip (any number of) switches to off/0 (aka "paused").
* If you want a pauseXYZ function that just flips a single bit / "pausing flag", it will:
* 1) 'bit-wise and' (aka `&`) a flag with the current paused state (as a uint256)
* 2) update the paused state to this new value
* @dev We note as well that we have chosen to identify flags by their *bit index* as opposed to their numerical value, so, e.g. defining `DEPOSITS_PAUSED = 3`
* indicates specifically that if the *third bit* of `_paused` is flipped -- i.e. it is a '1' -- then deposits should be paused
*/
contract Pausable is IPausable {
/// @notice Address of the `PauserRegistry` contract that this contract defers to for determining access control (for pausing).
IPauserRegistry public pauserRegistry;
/// @dev whether or not the contract is currently paused
uint256 private _paused;
uint256 constant internal UNPAUSE_ALL = 0;
uint256 constant internal PAUSE_ALL = type(uint256).max;
/// @notice Emitted when the `pauserRegistry` is set to `newPauserRegistry`.
event PauserRegistrySet(IPauserRegistry pauserRegistry, IPauserRegistry newPauserRegistry);
/// @notice Emitted when the pause is triggered by `account`, and changed to `newPausedStatus`.
event Paused(address indexed account, uint256 newPausedStatus);
/// @notice Emitted when the pause is lifted by `account`, and changed to `newPausedStatus`.
event Unpaused(address indexed account, uint256 newPausedStatus);
/// @notice
modifier onlyPauser() {
require(pauserRegistry.isPauser(msg.sender), "msg.sender is not permissioned as pauser");
_;
}
modifier onlyUnpauser() {
require(msg.sender == pauserRegistry.unpauser(), "msg.sender is not permissioned as unpauser");
_;
}
/// @notice Throws if the contract is paused, i.e. if any of the bits in `_paused` is flipped to 1.
modifier whenNotPaused() {
require(_paused == 0, "Pausable: contract is paused");
_;
}
/// @notice Throws if the `indexed`th bit of `_paused` is 1, i.e. if the `index`th pause switch is flipped.
modifier onlyWhenNotPaused(uint8 index) {
require(!paused(index), "Pausable: index is paused");
_;
}
/// @notice One-time function for setting the `pauserRegistry` and initializing the value of `_paused`.
function _initializePauser(IPauserRegistry _pauserRegistry, uint256 initPausedStatus) internal {
require(
address(pauserRegistry) == address(0) && address(_pauserRegistry) != address(0),
"Pausable._initializePauser: _initializePauser() can only be called once"
);
_paused = initPausedStatus;
emit Paused(msg.sender, initPausedStatus);
_setPauserRegistry(_pauserRegistry);
}
/**
* @notice This function is used to pause an EigenLayer contract's functionality.
* It is permissioned to the `pauser` address, which is expected to be a low threshold multisig.
* @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once.
* @dev This function can only pause functionality, and thus cannot 'unflip' any bit in `_paused` from 1 to 0.
*/
function pause(uint256 newPausedStatus) external onlyPauser {
// verify that the `newPausedStatus` does not *unflip* any bits (i.e. doesn't unpause anything, all 1 bits remain)
require((_paused & newPausedStatus) == _paused, "Pausable.pause: invalid attempt to unpause functionality");
_paused = newPausedStatus;
emit Paused(msg.sender, newPausedStatus);
}
/**
* @notice Alias for `pause(type(uint256).max)`.
*/
function pauseAll() external onlyPauser {
_paused = type(uint256).max;
emit Paused(msg.sender, type(uint256).max);
}
/**
* @notice This function is used to unpause an EigenLayer contract's functionality.
* It is permissioned to the `unpauser` address, which is expected to be a high threshold multisig or governance contract.
* @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once.
* @dev This function can only unpause functionality, and thus cannot 'flip' any bit in `_paused` from 0 to 1.
*/
function unpause(uint256 newPausedStatus) external onlyUnpauser {
// verify that the `newPausedStatus` does not *flip* any bits (i.e. doesn't pause anything, all 0 bits remain)
require(((~_paused) & (~newPausedStatus)) == (~_paused), "Pausable.unpause: invalid attempt to pause functionality");
_paused = newPausedStatus;
emit Unpaused(msg.sender, newPausedStatus);
}
/// @notice Returns the current paused status as a uint256.
function paused() public view virtual returns (uint256) {
return _paused;
}
/// @notice Returns 'true' if the `indexed`th bit of `_paused` is 1, and 'false' otherwise
function paused(uint8 index) public view virtual returns (bool) {
uint256 mask = 1 << index;
return ((_paused & mask) == mask);
}
/// @notice Allows the unpauser to set a new pauser registry
function setPauserRegistry(IPauserRegistry newPauserRegistry) external onlyUnpauser {
_setPauserRegistry(newPauserRegistry);
}
/// internal function for setting pauser registry
function _setPauserRegistry(IPauserRegistry newPauserRegistry) internal {
require(address(newPauserRegistry) != address(0), "Pausable._setPauserRegistry: newPauserRegistry cannot be the zero address");
emit PauserRegistrySet(pauserRegistry, newPauserRegistry);
pauserRegistry = newPauserRegistry;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[48] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @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]
* ```
* 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 Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 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. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_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.
*
* `initializer` is equivalent to `reinitializer(1)`, so 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.
*
* 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.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_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() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @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.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/**
* @title Minimal interface for an `Strategy` contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Custom `Strategy` implementations may expand extensively on this interface.
*/
interface IStrategy {
/**
* @notice Used to deposit tokens into this Strategy
* @param token is the ERC20 token being deposited
* @param amount is the amount of token being deposited
* @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
* `depositIntoStrategy` function, and individual share balances are recorded in the strategyManager as well.
* @return newShares is the number of new shares issued at the current exchange ratio.
*/
function deposit(IERC20 token, uint256 amount) external returns (uint256);
/**
* @notice Used to withdraw tokens from this Strategy, to the `depositor`'s address
* @param depositor is the address to receive the withdrawn funds
* @param token is the ERC20 token being transferred out
* @param amountShares is the amount of shares being withdrawn
* @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
* other functions, and individual share balances are recorded in the strategyManager as well.
*/
function withdraw(address depositor, IERC20 token, uint256 amountShares) external;
/**
* @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
* @notice In contrast to `sharesToUnderlyingView`, this function **may** make state modifications
* @param amountShares is the amount of shares to calculate its conversion into the underlying token
* @return The amount of underlying tokens corresponding to the input `amountShares`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function sharesToUnderlying(uint256 amountShares) external returns (uint256);
/**
* @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
* @notice In contrast to `underlyingToSharesView`, this function **may** make state modifications
* @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
* @return The amount of underlying tokens corresponding to the input `amountShares`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function underlyingToShares(uint256 amountUnderlying) external returns (uint256);
/**
* @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
* this strategy. In contrast to `userUnderlyingView`, this function **may** make state modifications
*/
function userUnderlying(address user) external returns (uint256);
/**
* @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
* @notice In contrast to `sharesToUnderlying`, this function guarantees no state modifications
* @param amountShares is the amount of shares to calculate its conversion into the underlying token
* @return The amount of shares corresponding to the input `amountUnderlying`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function sharesToUnderlyingView(uint256 amountShares) external view returns (uint256);
/**
* @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
* @notice In contrast to `underlyingToShares`, this function guarantees no state modifications
* @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
* @return The amount of shares corresponding to the input `amountUnderlying`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function underlyingToSharesView(uint256 amountUnderlying) external view returns (uint256);
/**
* @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
* this strategy. In contrast to `userUnderlying`, this function guarantees no state modifications
*/
function userUnderlyingView(address user) external view returns (uint256);
/// @notice The underlying token for shares in this Strategy
function underlyingToken() external view returns (IERC20);
/// @notice The total number of extant shares in this Strategy
function totalShares() external view returns (uint256);
/// @notice Returns either a brief string explaining the strategy's goal & purpose, or a link to metadata that explains in more detail.
function explanation() external view returns (string memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;
/**
* @title Interface for the primary 'slashing' contract for EigenLayer.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice See the `Slasher` contract itself for implementation details.
*/
interface ISlasher {
// struct used to store information about the current state of an operator's obligations to middlewares they are serving
struct MiddlewareTimes {
// The update block for the middleware whose most recent update was earliest, i.e. the 'stalest' update out of all middlewares the operator is serving
uint32 stalestUpdateBlock;
// The latest 'serveUntilBlock' from all of the middleware that the operator is serving
uint32 latestServeUntilBlock;
}
// struct used to store details relevant to a single middleware that an operator has opted-in to serving
struct MiddlewareDetails {
// the block before which the contract is allowed to slash the user
uint32 contractCanSlashOperatorUntilBlock;
// the block at which the middleware's view of the operator's stake was most recently updated
uint32 latestUpdateBlock;
}
/**
* @notice Gives the `contractAddress` permission to slash the funds of the caller.
* @dev Typically, this function must be called prior to registering for a middleware.
*/
function optIntoSlashing(address contractAddress) external;
/**
* @notice Used for 'slashing' a certain operator.
* @param toBeFrozen The operator to be frozen.
* @dev Technically the operator is 'frozen' (hence the name of this function), and then subject to slashing pending a decision by a human-in-the-loop.
* @dev The operator must have previously given the caller (which should be a contract) the ability to slash them, through a call to `optIntoSlashing`.
*/
function freezeOperator(address toBeFrozen) external;
/**
* @notice Removes the 'frozen' status from each of the `frozenAddresses`
* @dev Callable only by the contract owner (i.e. governance).
*/
function resetFrozenStatus(address[] calldata frozenAddresses) external;
/**
* @notice this function is a called by middlewares during an operator's registration to make sure the operator's stake at registration
* is slashable until serveUntil
* @param operator the operator whose stake update is being recorded
* @param serveUntilBlock the block until which the operator's stake at the current block is slashable
* @dev adds the middleware's slashing contract to the operator's linked list
*/
function recordFirstStakeUpdate(address operator, uint32 serveUntilBlock) external;
/**
* @notice this function is a called by middlewares during a stake update for an operator (perhaps to free pending withdrawals)
* to make sure the operator's stake at updateBlock is slashable until serveUntil
* @param operator the operator whose stake update is being recorded
* @param updateBlock the block for which the stake update is being recorded
* @param serveUntilBlock the block until which the operator's stake at updateBlock is slashable
* @param insertAfter the element of the operators linked list that the currently updating middleware should be inserted after
* @dev insertAfter should be calculated offchain before making the transaction that calls this. this is subject to race conditions,
* but it is anticipated to be rare and not detrimental.
*/
function recordStakeUpdate(address operator, uint32 updateBlock, uint32 serveUntilBlock, uint256 insertAfter) external;
/**
* @notice this function is a called by middlewares during an operator's deregistration to make sure the operator's stake at deregistration
* is slashable until serveUntil
* @param operator the operator whose stake update is being recorded
* @param serveUntilBlock the block until which the operator's stake at the current block is slashable
* @dev removes the middleware's slashing contract to the operator's linked list and revokes the middleware's (i.e. caller's) ability to
* slash `operator` once `serveUntil` is reached
*/
function recordLastStakeUpdateAndRevokeSlashingAbility(address operator, uint32 serveUntilBlock) external;
/**
* @notice Used to determine whether `staker` is actively 'frozen'. If a staker is frozen, then they are potentially subject to
* slashing of their funds, and cannot cannot deposit or withdraw from the strategyManager until the slashing process is completed
* and the staker's status is reset (to 'unfrozen').
* @param staker The staker of interest.
* @return Returns 'true' if `staker` themselves has their status set to frozen, OR if the staker is delegated
* to an operator who has their status set to frozen. Otherwise returns 'false'.
*/
function isFrozen(address staker) external view returns (bool);
/// @notice Returns true if `slashingContract` is currently allowed to slash `toBeSlashed`.
function canSlash(address toBeSlashed, address slashingContract) external view returns (bool);
/// @notice Returns the block until which `serviceContract` is allowed to slash the `operator`.
function contractCanSlashOperatorUntilBlock(address operator, address serviceContract) external view returns (uint32);
/// @notice Returns the block at which the `serviceContract` last updated its view of the `operator`'s stake
function latestUpdateBlock(address operator, address serviceContract) external view returns (uint32);
/// @notice A search routine for finding the correct input value of `insertAfter` to `recordStakeUpdate` / `_updateMiddlewareList`.
function getCorrectValueForInsertAfter(address operator, uint32 updateBlock) external view returns (uint256);
/**
* @notice Returns 'true' if `operator` can currently complete a withdrawal started at the `withdrawalStartBlock`, with `middlewareTimesIndex` used
* to specify the index of a `MiddlewareTimes` struct in the operator's list (i.e. an index in `operatorToMiddlewareTimes[operator]`). The specified
* struct is consulted as proof of the `operator`'s ability (or lack thereof) to complete the withdrawal.
* This function will return 'false' if the operator cannot currently complete a withdrawal started at the `withdrawalStartBlock`, *or* in the event
* that an incorrect `middlewareTimesIndex` is supplied, even if one or more correct inputs exist.
* @param operator Either the operator who queued the withdrawal themselves, or if the withdrawing party is a staker who delegated to an operator,
* this address is the operator *who the staker was delegated to* at the time of the `withdrawalStartBlock`.
* @param withdrawalStartBlock The block number at which the withdrawal was initiated.
* @param middlewareTimesIndex Indicates an index in `operatorToMiddlewareTimes[operator]` to consult as proof of the `operator`'s ability to withdraw
* @dev The correct `middlewareTimesIndex` input should be computable off-chain.
*/
function canWithdraw(address operator, uint32 withdrawalStartBlock, uint256 middlewareTimesIndex) external returns(bool);
/**
* operator =>
* [
* (
* the least recent update block of all of the middlewares it's serving/served,
* latest time that the stake bonded at that update needed to serve until
* )
* ]
*/
function operatorToMiddlewareTimes(address operator, uint256 arrayIndex) external view returns (MiddlewareTimes memory);
/// @notice Getter function for fetching `operatorToMiddlewareTimes[operator].length`
function middlewareTimesLength(address operator) external view returns (uint256);
/// @notice Getter function for fetching `operatorToMiddlewareTimes[operator][index].stalestUpdateBlock`.
function getMiddlewareTimesIndexBlock(address operator, uint32 index) external view returns(uint32);
/// @notice Getter function for fetching `operatorToMiddlewareTimes[operator][index].latestServeUntil`.
function getMiddlewareTimesIndexServeUntilBlock(address operator, uint32 index) external view returns(uint32);
/// @notice Getter function for fetching `_operatorToWhitelistedContractsByUpdate[operator].size`.
function operatorWhitelistedContractsLinkedListSize(address operator) external view returns (uint256);
/// @notice Getter function for fetching a single node in the operator's linked list (`_operatorToWhitelistedContractsByUpdate[operator]`).
function operatorWhitelistedContractsLinkedListEntry(address operator, address node) external view returns (bool, uint256, uint256);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;
import "./IDelegationTerms.sol";
/**
* @title The interface for the primary delegation contract for EigenLayer.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice This is the contract for delegation in EigenLayer. The main functionalities of this contract are
* - enabling anyone to register as an operator in EigenLayer
* - allowing new operators to provide a DelegationTerms-type contract, which may mediate their interactions with stakers who delegate to them
* - enabling any staker to delegate its stake to the operator of its choice
* - enabling a staker to undelegate its assets from an operator (performed as part of the withdrawal process, initiated through the StrategyManager)
*/
interface IDelegationManager {
/**
* @notice This will be called by an operator to register itself as an operator that stakers can choose to delegate to.
* @param dt is the `DelegationTerms` contract that the operator has for those who delegate to them.
* @dev An operator can set `dt` equal to their own address (or another EOA address), in the event that they want to split payments
* in a more 'trustful' manner.
* @dev In the present design, once set, there is no way for an operator to ever modify the address of their DelegationTerms contract.
*/
function registerAsOperator(IDelegationTerms dt) external;
/**
* @notice This will be called by a staker to delegate its assets to some operator.
* @param operator is the operator to whom staker (msg.sender) is delegating its assets
*/
function delegateTo(address operator) external;
/**
* @notice Delegates from `staker` to `operator`.
* @dev requires that:
* 1) if `staker` is an EOA, then `signature` is valid ECDSA signature from `staker`, indicating their intention for this action
* 2) if `staker` is a contract, then `signature` must will be checked according to EIP-1271
*/
function delegateToBySignature(address staker, address operator, uint256 expiry, bytes memory signature) external;
/**
* @notice Undelegates `staker` from the operator who they are delegated to.
* @notice Callable only by the StrategyManager
* @dev Should only ever be called in the event that the `staker` has no active deposits in EigenLayer.
*/
function undelegate(address staker) external;
/// @notice returns the address of the operator that `staker` is delegated to.
function delegatedTo(address staker) external view returns (address);
/// @notice returns the DelegationTerms of the `operator`, which may mediate their interactions with stakers who delegate to them.
function delegationTerms(address operator) external view returns (IDelegationTerms);
/// @notice returns the total number of shares in `strategy` that are delegated to `operator`.
function operatorShares(address operator, IStrategy strategy) external view returns (uint256);
/**
* @notice Increases the `staker`'s delegated shares in `strategy` by `shares, typically called when the staker has further deposits into EigenLayer
* @dev Callable only by the StrategyManager
*/
function increaseDelegatedShares(address staker, IStrategy strategy, uint256 shares) external;
/**
* @notice Decreases the `staker`'s delegated shares in each entry of `strategies` by its respective `shares[i]`, typically called when the staker withdraws from EigenLayer
* @dev Callable only by the StrategyManager
*/
function decreaseDelegatedShares(
address staker,
IStrategy[] calldata strategies,
uint256[] calldata shares
) external;
/// @notice Returns 'true' if `staker` *is* actively delegated, and 'false' otherwise.
function isDelegated(address staker) external view returns (bool);
/// @notice Returns 'true' if `staker` is *not* actively delegated, and 'false' otherwise.
function isNotDelegated(address staker) external view returns (bool);
/// @notice Returns if an operator can be delegated to, i.e. it has called `registerAsOperator`.
function isOperator(address operator) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;
import "../interfaces/IPauserRegistry.sol";
/**
* @title Adds pausability to a contract, with pausing & unpausing controlled by the `pauser` and `unpauser` of a PauserRegistry contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Contracts that inherit from this contract may define their own `pause` and `unpause` (and/or related) functions.
* These functions should be permissioned as "onlyPauser" which defers to a `PauserRegistry` for determining access control.
* @dev Pausability is implemented using a uint256, which allows up to 256 different single bit-flags; each bit can potentially pause different functionality.
* Inspiration for this was taken from the NearBridge design here https://etherscan.io/address/0x3FEFc5A4B1c02f21cBc8D3613643ba0635b9a873#code.
* For the `pause` and `unpause` functions we've implemented, if you pause, you can only flip (any number of) switches to on/1 (aka "paused"), and if you unpause,
* you can only flip (any number of) switches to off/0 (aka "paused").
* If you want a pauseXYZ function that just flips a single bit / "pausing flag", it will:
* 1) 'bit-wise and' (aka `&`) a flag with the current paused state (as a uint256)
* 2) update the paused state to this new value
* @dev We note as well that we have chosen to identify flags by their *bit index* as opposed to their numerical value, so, e.g. defining `DEPOSITS_PAUSED = 3`
* indicates specifically that if the *third bit* of `_paused` is flipped -- i.e. it is a '1' -- then deposits should be paused
*/
interface IPausable {
/// @notice Address of the `PauserRegistry` contract that this contract defers to for determining access control (for pausing).
function pauserRegistry() external view returns (IPauserRegistry);
/**
* @notice This function is used to pause an EigenLayer contract's functionality.
* It is permissioned to the `pauser` address, which is expected to be a low threshold multisig.
* @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once.
* @dev This function can only pause functionality, and thus cannot 'unflip' any bit in `_paused` from 1 to 0.
*/
function pause(uint256 newPausedStatus) external;
/**
* @notice Alias for `pause(type(uint256).max)`.
*/
function pauseAll() external;
/**
* @notice This function is used to unpause an EigenLayer contract's functionality.
* It is permissioned to the `unpauser` address, which is expected to be a high threshold multisig or governance contract.
* @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once.
* @dev This function can only unpause functionality, and thus cannot 'flip' any bit in `_paused` from 0 to 1.
*/
function unpause(uint256 newPausedStatus) external;
/// @notice Returns the current paused status as a uint256.
function paused() external view returns (uint256);
/// @notice Returns 'true' if the `indexed`th bit of `_paused` is 1, and 'false' otherwise
function paused(uint8 index) external view returns (bool);
/// @notice Allows the unpauser to set a new pauser registry
function setPauserRegistry(IPauserRegistry newPauserRegistry) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;
import "./IStrategy.sol";
/**
* @title Abstract interface for a contract that helps structure the delegation relationship.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice The gas budget provided to this contract in calls from EigenLayer contracts is limited.
*/
interface IDelegationTerms {
function payForService(IERC20 token, uint256 amount) external payable;
function onDelegationWithdrawn(
address delegator,
IStrategy[] memory stakerStrategyList,
uint256[] memory stakerShares
) external returns(bytes memory);
function onDelegationReceived(
address delegator,
IStrategy[] memory stakerStrategyList,
uint256[] memory stakerShares
) external returns(bytes memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;
/**
* @title Interface for the `PauserRegistry` contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
*/
interface IPauserRegistry {
/// @notice Mapping of addresses to whether they hold the pauser role.
function isPauser(address pauser) external view returns (bool);
/// @notice Unique address that holds the unpauser role. Capable of changing *both* the pauser and unpauser addresses.
function unpauser() external view returns (address);
}{
"remappings": [
"@openzeppelin-upgrades/=lib/openzeppelin-contracts-upgradeable/",
"@openzeppelin/=lib/openzeppelin-contracts/",
"ds-test/=lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IStrategyManager","name":"_strategyManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"previousValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"MaxPerDepositUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"previousValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"MaxTotalDepositsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IPauserRegistry","name":"pauserRegistry","type":"address"},{"indexed":false,"internalType":"contract IPauserRegistry","name":"newPauserRegistry","type":"address"}],"name":"PauserRegistrySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"newShares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"explanation","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTVLLimits","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxPerDeposit","type":"uint256"},{"internalType":"uint256","name":"_maxTotalDeposits","type":"uint256"},{"internalType":"contract IERC20","name":"_underlyingToken","type":"address"},{"internalType":"contract IPauserRegistry","name":"_pauserRegistry","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_underlyingToken","type":"address"},{"internalType":"contract IPauserRegistry","name":"_pauserRegistry","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxPerDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTotalDeposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauserRegistry","outputs":[{"internalType":"contract IPauserRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IPauserRegistry","name":"newPauserRegistry","type":"address"}],"name":"setPauserRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMaxPerDeposit","type":"uint256"},{"internalType":"uint256","name":"newMaxTotalDeposits","type":"uint256"}],"name":"setTVLLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"shares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountShares","type":"uint256"}],"name":"sharesToUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountShares","type":"uint256"}],"name":"sharesToUnderlyingView","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategyManager","outputs":[{"internalType":"contract IStrategyManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountUnderlying","type":"uint256"}],"name":"underlyingToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountUnderlying","type":"uint256"}],"name":"underlyingToSharesView","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlyingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"userUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"userUnderlyingView","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"depositor","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amountShares","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a06040523480156200001157600080fd5b5060405162001d5638038062001d56833981016040819052620000349162000116565b6001600160a01b038116608052806200004c62000054565b505062000148565b600054610100900460ff1615620000c15760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116101562000114576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6000602082840312156200012957600080fd5b81516001600160a01b03811681146200014157600080fd5b9392505050565b608051611bdd6200017960003960008181610216015281816107a901528181610bc30152610c8e0152611bdd6000f3fe608060405234801561001057600080fd5b506004361061018e5760003560e01c80635c975abb116100de578063ab5921e111610097578063df6fadc111610071578063df6fadc114610366578063e3dae51c14610381578063f3e7387514610394578063fabc1cbc146103a757600080fd5b8063ab5921e11461032b578063ce7c2ac214610340578063d9caed121461035357600080fd5b80635c975abb146102c857806361b01b5d146102d05780637a8b2637146102d9578063886f1195146102ec5780638c871019146103055780638f6a62401461031857600080fd5b80633a98ef391161014b578063485cc95511610125578063485cc9551461026b578063553ca5f81461027e578063595c6a67146102915780635ac86ab71461029957600080fd5b80633a98ef391461023857806343fe08b01461024f57806347e7ef241461025857600080fd5b8063019e27291461019357806310d67a2f146101a857806311c70c9d146101bb578063136439dd146101ce5780632495a599146101e157806339b70e3814610211575b600080fd5b6101a66101a13660046117b2565b6103ba565b005b6101a66101b63660046117fc565b61049d565b6101a66101c9366004611819565b610550565b6101a66101dc36600461183b565b610605565b6032546101f4906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101f47f000000000000000000000000000000000000000000000000000000000000000081565b61024160335481565b604051908152602001610208565b61024160645481565b610241610266366004611854565b610749565b6101a6610279366004611880565b610969565b61024161028c3660046117fc565b610a37565b6101a6610a4b565b6102b86102a73660046118b9565b6001805460ff9092161b9081161490565b6040519015158152602001610208565b600154610241565b61024160655481565b6102416102e736600461183b565b610b17565b6000546101f4906201000090046001600160a01b031681565b61024161031336600461183b565b610b62565b6102416103263660046117fc565b610b6d565b610333610b7b565b604051610208919061190c565b61024161034e3660046117fc565b610b9b565b6101a661036136600461193f565b610c30565b60645460655460408051928352602083019190915201610208565b61024161038f36600461183b565b610e7d565b6102416103a236600461183b565b610eb6565b6101a66103b536600461183b565b610ec1565b600054610100900460ff16158080156103da5750600054600160ff909116105b806103f45750303b1580156103f4575060005460ff166001145b6104195760405162461bcd60e51b815260040161041090611980565b60405180910390fd5b6000805460ff19166001179055801561043c576000805461ff0019166101001790555b610446858561101d565b610450838361112a565b8015610496576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051491906119ce565b6001600160a01b0316336001600160a01b0316146105445760405162461bcd60e51b8152600401610410906119eb565b61054d816111bb565b50565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c791906119ce565b6001600160a01b0316336001600160a01b0316146105f75760405162461bcd60e51b8152600401610410906119eb565b610601828261101d565b5050565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa158015610652573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106769190611a35565b6106925760405162461bcd60e51b815260040161041090611a57565b6001548181161461070b5760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e70617573653a20696e76616c696420617474656d70742060448201527f746f20756e70617573652066756e6374696f6e616c69747900000000000000006064820152608401610410565b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b6001805460009182918116141561079e5760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b6044820152606401610410565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146108165760405162461bcd60e51b815260206004820181905260248201527f5374726174656779426173652e6f6e6c7953747261746567794d616e616765726044820152606401610410565b61082084846112c0565b6032546001600160a01b0385811691161461089c5760405162461bcd60e51b815260206004820152603660248201527f5374726174656779426173652e6465706f7369743a2043616e206f6e6c79206460448201527532b837b9b4ba103ab73232b9363cb4b733aa37b5b2b760511b6064820152608401610410565b60335460006108ad6103e883611ab5565b905060006103e86108bc611398565b6108c69190611ab5565b905060006108d48783611acd565b9050806108e18489611ae4565b6108eb9190611b03565b9550856109515760405162461bcd60e51b815260206004820152602e60248201527f5374726174656779426173652e6465706f7369743a206e65775368617265732060448201526d63616e6e6f74206265207a65726f60901b6064820152608401610410565b61095b8685611ab5565b603355505050505092915050565b600054610100900460ff16158080156109895750600054600160ff909116105b806109a35750303b1580156109a3575060005460ff166001145b6109bf5760405162461bcd60e51b815260040161041090611980565b6000805460ff1916600117905580156109e2576000805461ff0019166101001790555b6109ec838361112a565b8015610a32576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6000610a456102e783610b9b565b92915050565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa158015610a98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610abc9190611a35565b610ad85760405162461bcd60e51b815260040161041090611a57565b600019600181905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b6000806103e8603354610b2a9190611ab5565b905060006103e8610b39611398565b610b439190611ab5565b905081610b508583611ae4565b610b5a9190611b03565b949350505050565b6000610a4582610e7d565b6000610a456103a283610b9b565b60606040518060800160405280604d8152602001611b5b604d9139905090565b604051633d3f06c960e11b81526001600160a01b0382811660048301523060248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690637a7e0d9290604401602060405180830381865afa158015610c0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a459190611b25565b6001805460029081161415610c835760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b6044820152606401610410565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610cfb5760405162461bcd60e51b815260206004820181905260248201527f5374726174656779426173652e6f6e6c7953747261746567794d616e616765726044820152606401610410565b6032546001600160a01b03848116911614610d7e5760405162461bcd60e51b815260206004820152603b60248201527f5374726174656779426173652e77697468647261773a2043616e206f6e6c792060448201527f77697468647261772074686520737472617465677920746f6b656e00000000006064820152608401610410565b60335480831115610e0d5760405162461bcd60e51b815260206004820152604d60248201527f5374726174656779426173652e77697468647261773a20616d6f756e7453686160448201527f726573206d757374206265206c657373207468616e206f7220657175616c207460648201526c6f20746f74616c53686172657360981b608482015260a401610410565b6000610e1b6103e883611ab5565b905060006103e8610e2a611398565b610e349190611ab5565b9050600082610e438784611ae4565b610e4d9190611b03565b9050610e598685611acd565b603355603254610e73906001600160a01b0316898361140a565b5050505050505050565b6000806103e8603354610e909190611ab5565b905060006103e8610e9f611398565b610ea99190611ab5565b905080610b508386611ae4565b6000610a4582610b17565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3891906119ce565b6001600160a01b0316336001600160a01b031614610f685760405162461bcd60e51b8152600401610410906119eb565b600154198119600154191614610fe65760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e756e70617573653a20696e76616c696420617474656d7060448201527f7420746f2070617573652066756e6374696f6e616c69747900000000000000006064820152608401610410565b600181905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c9060200161073e565b60645460408051918252602082018490527ff97ed4e083acac67830025ecbc756d8fe847cdbdca4cee3fe1e128e98b54ecb5910160405180910390a160655460408051918252602082018390527f6ab181e0440bfbf4bacdf2e99674735ce6638005490688c5f994f5399353e452910160405180910390a18082111561111f5760405162461bcd60e51b815260206004820152604b60248201527f53747261746567794261736554564c4c696d6974732e5f73657454564c4c696d60448201527f6974733a206d61785065724465706f7369742065786365656473206d6178546f60648201526a74616c4465706f7369747360a81b608482015260a401610410565b606491909155606555565b600054610100900460ff166111955760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610410565b603280546001600160a01b0319166001600160a01b03841617905561060181600061145c565b6001600160a01b0381166112495760405162461bcd60e51b815260206004820152604960248201527f5061757361626c652e5f73657450617573657252656769737472793a206e657760448201527f50617573657252656769737472792063616e6e6f7420626520746865207a65726064820152686f206164647265737360b81b608482015260a401610410565b600054604080516001600160a01b03620100009093048316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b60645481111561132a5760405162461bcd60e51b815260206004820152602f60248201527f53747261746567794261736554564c4c696d6974733a206d617820706572206460448201526e195c1bdcda5d08195e18d959591959608a1b6064820152608401610410565b606554611335611398565b11156106015760405162461bcd60e51b815260206004820152602c60248201527f53747261746567794261736554564c4c696d6974733a206d6178206465706f7360448201526b1a5d1cc8195e18d95959195960a21b6064820152608401610410565b6032546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa1580156113e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114059190611b25565b905090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610a32908490611548565b6000546201000090046001600160a01b031615801561148357506001600160a01b03821615155b6115055760405162461bcd60e51b815260206004820152604760248201527f5061757361626c652e5f696e697469616c697a655061757365723a205f696e6960448201527f7469616c697a6550617573657228292063616e206f6e6c792062652063616c6c6064820152666564206f6e636560c81b608482015260a401610410565b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2610601826111bb565b600061159d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661161a9092919063ffffffff16565b805190915015610a3257808060200190518101906115bb9190611a35565b610a325760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610410565b60606116298484600085611633565b90505b9392505050565b6060824710156116945760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610410565b6001600160a01b0385163b6116eb5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610410565b600080866001600160a01b031685876040516117079190611b3e565b60006040518083038185875af1925050503d8060008114611744576040519150601f19603f3d011682016040523d82523d6000602084013e611749565b606091505b5091509150611759828286611764565b979650505050505050565b6060831561177357508161162c565b8251156117835782518084602001fd5b8160405162461bcd60e51b8152600401610410919061190c565b6001600160a01b038116811461054d57600080fd5b600080600080608085870312156117c857600080fd5b843593506020850135925060408501356117e18161179d565b915060608501356117f18161179d565b939692955090935050565b60006020828403121561180e57600080fd5b813561162c8161179d565b6000806040838503121561182c57600080fd5b50508035926020909101359150565b60006020828403121561184d57600080fd5b5035919050565b6000806040838503121561186757600080fd5b82356118728161179d565b946020939093013593505050565b6000806040838503121561189357600080fd5b823561189e8161179d565b915060208301356118ae8161179d565b809150509250929050565b6000602082840312156118cb57600080fd5b813560ff8116811461162c57600080fd5b60005b838110156118f75781810151838201526020016118df565b83811115611906576000848401525b50505050565b602081526000825180602084015261192b8160408501602087016118dc565b601f01601f19169190910160400192915050565b60008060006060848603121561195457600080fd5b833561195f8161179d565b9250602084013561196f8161179d565b929592945050506040919091013590565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6000602082840312156119e057600080fd5b815161162c8161179d565b6020808252602a908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526939903ab73830bab9b2b960b11b606082015260800190565b600060208284031215611a4757600080fd5b8151801515811461162c57600080fd5b60208082526028908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526739903830bab9b2b960c11b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b60008219821115611ac857611ac8611a9f565b500190565b600082821015611adf57611adf611a9f565b500390565b6000816000190483118215151615611afe57611afe611a9f565b500290565b600082611b2057634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215611b3757600080fd5b5051919050565b60008251611b508184602087016118dc565b919091019291505056fe4261736520537472617465677920696d706c656d656e746174696f6e20746f20696e68657269742066726f6d20666f72206d6f726520636f6d706c657820696d706c656d656e746174696f6e73a26469706673582212202583a8bcbb64c4e30925cb998998eae461ebff47bced45607523055fe8ad391364736f6c634300080c0033000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061018e5760003560e01c80635c975abb116100de578063ab5921e111610097578063df6fadc111610071578063df6fadc114610366578063e3dae51c14610381578063f3e7387514610394578063fabc1cbc146103a757600080fd5b8063ab5921e11461032b578063ce7c2ac214610340578063d9caed121461035357600080fd5b80635c975abb146102c857806361b01b5d146102d05780637a8b2637146102d9578063886f1195146102ec5780638c871019146103055780638f6a62401461031857600080fd5b80633a98ef391161014b578063485cc95511610125578063485cc9551461026b578063553ca5f81461027e578063595c6a67146102915780635ac86ab71461029957600080fd5b80633a98ef391461023857806343fe08b01461024f57806347e7ef241461025857600080fd5b8063019e27291461019357806310d67a2f146101a857806311c70c9d146101bb578063136439dd146101ce5780632495a599146101e157806339b70e3814610211575b600080fd5b6101a66101a13660046117b2565b6103ba565b005b6101a66101b63660046117fc565b61049d565b6101a66101c9366004611819565b610550565b6101a66101dc36600461183b565b610605565b6032546101f4906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101f47f000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a81565b61024160335481565b604051908152602001610208565b61024160645481565b610241610266366004611854565b610749565b6101a6610279366004611880565b610969565b61024161028c3660046117fc565b610a37565b6101a6610a4b565b6102b86102a73660046118b9565b6001805460ff9092161b9081161490565b6040519015158152602001610208565b600154610241565b61024160655481565b6102416102e736600461183b565b610b17565b6000546101f4906201000090046001600160a01b031681565b61024161031336600461183b565b610b62565b6102416103263660046117fc565b610b6d565b610333610b7b565b604051610208919061190c565b61024161034e3660046117fc565b610b9b565b6101a661036136600461193f565b610c30565b60645460655460408051928352602083019190915201610208565b61024161038f36600461183b565b610e7d565b6102416103a236600461183b565b610eb6565b6101a66103b536600461183b565b610ec1565b600054610100900460ff16158080156103da5750600054600160ff909116105b806103f45750303b1580156103f4575060005460ff166001145b6104195760405162461bcd60e51b815260040161041090611980565b60405180910390fd5b6000805460ff19166001179055801561043c576000805461ff0019166101001790555b610446858561101d565b610450838361112a565b8015610496576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051491906119ce565b6001600160a01b0316336001600160a01b0316146105445760405162461bcd60e51b8152600401610410906119eb565b61054d816111bb565b50565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c791906119ce565b6001600160a01b0316336001600160a01b0316146105f75760405162461bcd60e51b8152600401610410906119eb565b610601828261101d565b5050565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa158015610652573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106769190611a35565b6106925760405162461bcd60e51b815260040161041090611a57565b6001548181161461070b5760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e70617573653a20696e76616c696420617474656d70742060448201527f746f20756e70617573652066756e6374696f6e616c69747900000000000000006064820152608401610410565b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b6001805460009182918116141561079e5760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b6044820152606401610410565b336001600160a01b037f000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a16146108165760405162461bcd60e51b815260206004820181905260248201527f5374726174656779426173652e6f6e6c7953747261746567794d616e616765726044820152606401610410565b61082084846112c0565b6032546001600160a01b0385811691161461089c5760405162461bcd60e51b815260206004820152603660248201527f5374726174656779426173652e6465706f7369743a2043616e206f6e6c79206460448201527532b837b9b4ba103ab73232b9363cb4b733aa37b5b2b760511b6064820152608401610410565b60335460006108ad6103e883611ab5565b905060006103e86108bc611398565b6108c69190611ab5565b905060006108d48783611acd565b9050806108e18489611ae4565b6108eb9190611b03565b9550856109515760405162461bcd60e51b815260206004820152602e60248201527f5374726174656779426173652e6465706f7369743a206e65775368617265732060448201526d63616e6e6f74206265207a65726f60901b6064820152608401610410565b61095b8685611ab5565b603355505050505092915050565b600054610100900460ff16158080156109895750600054600160ff909116105b806109a35750303b1580156109a3575060005460ff166001145b6109bf5760405162461bcd60e51b815260040161041090611980565b6000805460ff1916600117905580156109e2576000805461ff0019166101001790555b6109ec838361112a565b8015610a32576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6000610a456102e783610b9b565b92915050565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa158015610a98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610abc9190611a35565b610ad85760405162461bcd60e51b815260040161041090611a57565b600019600181905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b6000806103e8603354610b2a9190611ab5565b905060006103e8610b39611398565b610b439190611ab5565b905081610b508583611ae4565b610b5a9190611b03565b949350505050565b6000610a4582610e7d565b6000610a456103a283610b9b565b60606040518060800160405280604d8152602001611b5b604d9139905090565b604051633d3f06c960e11b81526001600160a01b0382811660048301523060248301526000917f000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a90911690637a7e0d9290604401602060405180830381865afa158015610c0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a459190611b25565b6001805460029081161415610c835760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b6044820152606401610410565b336001600160a01b037f000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a1614610cfb5760405162461bcd60e51b815260206004820181905260248201527f5374726174656779426173652e6f6e6c7953747261746567794d616e616765726044820152606401610410565b6032546001600160a01b03848116911614610d7e5760405162461bcd60e51b815260206004820152603b60248201527f5374726174656779426173652e77697468647261773a2043616e206f6e6c792060448201527f77697468647261772074686520737472617465677920746f6b656e00000000006064820152608401610410565b60335480831115610e0d5760405162461bcd60e51b815260206004820152604d60248201527f5374726174656779426173652e77697468647261773a20616d6f756e7453686160448201527f726573206d757374206265206c657373207468616e206f7220657175616c207460648201526c6f20746f74616c53686172657360981b608482015260a401610410565b6000610e1b6103e883611ab5565b905060006103e8610e2a611398565b610e349190611ab5565b9050600082610e438784611ae4565b610e4d9190611b03565b9050610e598685611acd565b603355603254610e73906001600160a01b0316898361140a565b5050505050505050565b6000806103e8603354610e909190611ab5565b905060006103e8610e9f611398565b610ea99190611ab5565b905080610b508386611ae4565b6000610a4582610b17565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3891906119ce565b6001600160a01b0316336001600160a01b031614610f685760405162461bcd60e51b8152600401610410906119eb565b600154198119600154191614610fe65760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e756e70617573653a20696e76616c696420617474656d7060448201527f7420746f2070617573652066756e6374696f6e616c69747900000000000000006064820152608401610410565b600181905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c9060200161073e565b60645460408051918252602082018490527ff97ed4e083acac67830025ecbc756d8fe847cdbdca4cee3fe1e128e98b54ecb5910160405180910390a160655460408051918252602082018390527f6ab181e0440bfbf4bacdf2e99674735ce6638005490688c5f994f5399353e452910160405180910390a18082111561111f5760405162461bcd60e51b815260206004820152604b60248201527f53747261746567794261736554564c4c696d6974732e5f73657454564c4c696d60448201527f6974733a206d61785065724465706f7369742065786365656473206d6178546f60648201526a74616c4465706f7369747360a81b608482015260a401610410565b606491909155606555565b600054610100900460ff166111955760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610410565b603280546001600160a01b0319166001600160a01b03841617905561060181600061145c565b6001600160a01b0381166112495760405162461bcd60e51b815260206004820152604960248201527f5061757361626c652e5f73657450617573657252656769737472793a206e657760448201527f50617573657252656769737472792063616e6e6f7420626520746865207a65726064820152686f206164647265737360b81b608482015260a401610410565b600054604080516001600160a01b03620100009093048316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b60645481111561132a5760405162461bcd60e51b815260206004820152602f60248201527f53747261746567794261736554564c4c696d6974733a206d617820706572206460448201526e195c1bdcda5d08195e18d959591959608a1b6064820152608401610410565b606554611335611398565b11156106015760405162461bcd60e51b815260206004820152602c60248201527f53747261746567794261736554564c4c696d6974733a206d6178206465706f7360448201526b1a5d1cc8195e18d95959195960a21b6064820152608401610410565b6032546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa1580156113e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114059190611b25565b905090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610a32908490611548565b6000546201000090046001600160a01b031615801561148357506001600160a01b03821615155b6115055760405162461bcd60e51b815260206004820152604760248201527f5061757361626c652e5f696e697469616c697a655061757365723a205f696e6960448201527f7469616c697a6550617573657228292063616e206f6e6c792062652063616c6c6064820152666564206f6e636560c81b608482015260a401610410565b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2610601826111bb565b600061159d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661161a9092919063ffffffff16565b805190915015610a3257808060200190518101906115bb9190611a35565b610a325760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610410565b60606116298484600085611633565b90505b9392505050565b6060824710156116945760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610410565b6001600160a01b0385163b6116eb5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610410565b600080866001600160a01b031685876040516117079190611b3e565b60006040518083038185875af1925050503d8060008114611744576040519150601f19603f3d011682016040523d82523d6000602084013e611749565b606091505b5091509150611759828286611764565b979650505050505050565b6060831561177357508161162c565b8251156117835782518084602001fd5b8160405162461bcd60e51b8152600401610410919061190c565b6001600160a01b038116811461054d57600080fd5b600080600080608085870312156117c857600080fd5b843593506020850135925060408501356117e18161179d565b915060608501356117f18161179d565b939692955090935050565b60006020828403121561180e57600080fd5b813561162c8161179d565b6000806040838503121561182c57600080fd5b50508035926020909101359150565b60006020828403121561184d57600080fd5b5035919050565b6000806040838503121561186757600080fd5b82356118728161179d565b946020939093013593505050565b6000806040838503121561189357600080fd5b823561189e8161179d565b915060208301356118ae8161179d565b809150509250929050565b6000602082840312156118cb57600080fd5b813560ff8116811461162c57600080fd5b60005b838110156118f75781810151838201526020016118df565b83811115611906576000848401525b50505050565b602081526000825180602084015261192b8160408501602087016118dc565b601f01601f19169190910160400192915050565b60008060006060848603121561195457600080fd5b833561195f8161179d565b9250602084013561196f8161179d565b929592945050506040919091013590565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6000602082840312156119e057600080fd5b815161162c8161179d565b6020808252602a908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526939903ab73830bab9b2b960b11b606082015260800190565b600060208284031215611a4757600080fd5b8151801515811461162c57600080fd5b60208082526028908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526739903830bab9b2b960c11b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b60008219821115611ac857611ac8611a9f565b500190565b600082821015611adf57611adf611a9f565b500390565b6000816000190483118215151615611afe57611afe611a9f565b500290565b600082611b2057634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215611b3757600080fd5b5051919050565b60008251611b508184602087016118dc565b919091019291505056fe4261736520537472617465677920696d706c656d656e746174696f6e20746f20696e68657269742066726f6d20666f72206d6f726520636f6d706c657820696d706c656d656e746174696f6e73a26469706673582212202583a8bcbb64c4e30925cb998998eae461ebff47bced45607523055fe8ad391364736f6c634300080c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a
-----Decoded View---------------
Arg [0] : _strategyManager (address): 0x858646372CC42E1A627fcE94aa7A7033e7CF075A
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.