Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 20226637 | 58 days ago | IN | 0 ETH | 0.06430648 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
OperatorDelegator
Compiler Version
v0.8.19+commit.7dd6d404
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.19; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "../Permissions/IRoleManager.sol"; import "./OperatorDelegatorStorage.sol"; import "../EigenLayer/interfaces/IDelegationManager.sol"; import "../EigenLayer/interfaces/ISignatureUtils.sol"; import "../EigenLayer/libraries/BeaconChainProofs.sol"; import "../Errors/Errors.sol"; /// @dev This contract will be responsible for interacting with Eigenlayer /// Each of these contracts deployed will be delegated to one specific operator /// This contract can handle multiple ERC20 tokens, all of which will be delegated to the same operator /// Each supported ERC20 token will be pointed at a single Strategy contract in EL /// Only the RestakeManager should be interacting with this contract for EL interactions. contract OperatorDelegator is Initializable, ReentrancyGuardUpgradeable, OperatorDelegatorStorageV4 { using SafeERC20 for IERC20; using BeaconChainProofs for *; uint256 internal constant GWEI_TO_WEI = 1e9; address public constant IS_NATIVE = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /// @dev Max stakedButNotVerifiedEth amount cap per validator uint256 public constant MAX_STAKE_BUT_NOT_VERIFIED_AMOUNT = 32 ether; /// @dev Nominal base gas spent value by admin uint256 internal constant NOMINAL_BASE_GAS_SPENT = 50_000; event TokenStrategyUpdated(IERC20 token, IStrategy strategy); event DelegationAddressUpdated(address delegateAddress); event RewardsForwarded(address rewardDestination, uint256 amount); event WithdrawStarted( bytes32 withdrawRoot, address staker, address delegatedTo, address withdrawer, uint nonce, uint startBlock, IStrategy[] strategies, uint256[] shares ); event WithdrawCompleted(bytes32 withdrawalRoot, IStrategy[] strategies, uint256[] shares); event GasSpent(address admin, uint256 gasSpent); event GasRefunded(address admin, uint256 gasRefunded); event BaseGasAmountSpentUpdated(uint256 oldBaseGasAmountSpent, uint256 newBaseGasAmountSpent); /// @dev Allows only a whitelisted address to configure the contract modifier onlyOperatorDelegatorAdmin() { if (!roleManager.isOperatorDelegatorAdmin(msg.sender)) revert NotOperatorDelegatorAdmin(); _; } /// @dev Allows only the RestakeManager address to call functions modifier onlyRestakeManager() { if (msg.sender != address(restakeManager)) revert NotRestakeManager(); _; } /// @dev Allows only a whitelisted address to configure the contract modifier onlyNativeEthRestakeAdmin() { if (!roleManager.isNativeEthRestakeAdmin(msg.sender)) revert NotNativeEthRestakeAdmin(); _; } modifier onlyEmergencyWithdrawTrackingAdmin() { if (!roleManager.isEmergencyWithdrawTrackingAdmin(msg.sender)) revert NotEmergencyWithdrawTrackingAdmin(); _; } /// @dev Prevents implementation contract from being initialized. /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /// @dev Initializes the contract with initial vars function initialize( IRoleManager _roleManager, IStrategyManager _strategyManager, IRestakeManager _restakeManager, IDelegationManager _delegationManager, IEigenPodManager _eigenPodManager ) external initializer { if (address(_roleManager) == address(0x0)) revert InvalidZeroInput(); if (address(_strategyManager) == address(0x0)) revert InvalidZeroInput(); if (address(_restakeManager) == address(0x0)) revert InvalidZeroInput(); if (address(_delegationManager) == address(0x0)) revert InvalidZeroInput(); if (address(_eigenPodManager) == address(0x0)) revert InvalidZeroInput(); __ReentrancyGuard_init(); roleManager = _roleManager; strategyManager = _strategyManager; restakeManager = _restakeManager; delegationManager = _delegationManager; eigenPodManager = _eigenPodManager; // Deploy new EigenPod eigenPod = IEigenPod(eigenPodManager.createPod()); } /// @dev Migrates the M1 pods to M2 pods by calling activateRestaking on eigenPod /// @dev Should be a permissioned call by onlyNativeEthRestakeAdmin function activateRestaking() external nonReentrant onlyNativeEthRestakeAdmin { eigenPod.activateRestaking(); } /// @dev Sets the strategy for a given token - setting strategy to 0x0 removes the ability to deposit and withdraw token function setTokenStrategy( IERC20 _token, IStrategy _strategy ) external nonReentrant onlyOperatorDelegatorAdmin { if (address(_token) == address(0x0)) revert InvalidZeroInput(); // check revert if strategy underlying does not match if ( address(_strategy) != address(0x0) && ((_strategy.underlyingToken() != _token) || !strategyManager.strategyIsWhitelistedForDeposit(_strategy)) ) revert InvalidStrategy(); // check revert if strategy already set and shares greater than 0 if ( address(tokenStrategyMapping[_token]) != address(0x0) && tokenStrategyMapping[_token].userUnderlyingView(address(this)) > 0 ) revert NonZeroUnderlyingStrategyExist(); tokenStrategyMapping[_token] = _strategy; emit TokenStrategyUpdated(_token, _strategy); } /// @dev Sets the address to delegate tokens to in EigenLayer -- THIS CAN ONLY BE SET ONCE function setDelegateAddress( address _delegateAddress, ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry, bytes32 approverSalt ) external nonReentrant onlyOperatorDelegatorAdmin { if (address(_delegateAddress) == address(0x0)) revert InvalidZeroInput(); if (address(delegateAddress) != address(0x0)) revert DelegateAddressAlreadySet(); delegateAddress = _delegateAddress; delegationManager.delegateTo(delegateAddress, approverSignatureAndExpiry, approverSalt); emit DelegationAddressUpdated(_delegateAddress); } function setBaseGasAmountSpent( uint256 _baseGasAmountSpent ) external nonReentrant onlyOperatorDelegatorAdmin { if (_baseGasAmountSpent == 0) revert InvalidZeroInput(); emit BaseGasAmountSpentUpdated(baseGasAmountSpent, _baseGasAmountSpent); baseGasAmountSpent = _baseGasAmountSpent; } /// @dev Deposit tokens into the EigenLayer. This call assumes any balance of tokens in this contract will be delegated /// so do not directly send tokens here or they will be delegated and attributed to the next caller. /// @return shares The amount of new shares in the `strategy` created as part of the action. function deposit( IERC20 token, uint256 tokenAmount ) external nonReentrant onlyRestakeManager returns (uint256 shares) { if (address(tokenStrategyMapping[token]) == address(0x0) || tokenAmount == 0) revert InvalidZeroInput(); // Move the tokens into this contract token.safeTransferFrom(msg.sender, address(this), tokenAmount); return _deposit(token, tokenAmount); } /** * @notice Perform necessary checks on input data and deposits into EigenLayer * @param _token token interface to deposit * @param _tokenAmount amount of given token to deposit * @return shares shares for deposited amount */ function _deposit(IERC20 _token, uint256 _tokenAmount) internal returns (uint256 shares) { // Approve the strategy manager to spend the tokens _token.safeIncreaseAllowance(address(strategyManager), _tokenAmount); // Deposit the tokens via the strategy manager return strategyManager.depositIntoStrategy(tokenStrategyMapping[_token], _token, _tokenAmount); } /// @dev Gets the index of the specific strategy in EigenLayer in the staker's strategy list function getStrategyIndex(IStrategy _strategy) public view returns (uint256) { // Get the length of the strategy list for this contract uint256 strategyLength = strategyManager.stakerStrategyListLength(address(this)); for (uint256 i = 0; i < strategyLength; i++) { if (strategyManager.stakerStrategyList(address(this), i) == _strategy) { return i; } } // Not found revert NotFound(); } /** * @notice Tracks the pending queued withdrawal shares cause by Operator force undelegating the OperatorDelegator * @dev permissioned call (onlyEmergencyWithdrawTrackingAdmin), * each withdrawal will contain single strategy and respective shares in case of 'ForceUndelegation'. * EigenLayer link - https://github.com/Layr-Labs/eigenlayer-contracts/blob/dev/src/contracts/core/DelegationManager.sol#L242 * @param withdrawals Withdrawals struct list needs to be tracked * @param tokens list of Tokens undelegated by Operator */ function emergencyTrackQueuedWithdrawals( IDelegationManager.Withdrawal[] calldata withdrawals, IERC20[] calldata tokens ) external nonReentrant onlyEmergencyWithdrawTrackingAdmin { // verify array lengths if (tokens.length != withdrawals.length) revert MismatchedArrayLengths(); for (uint256 i = 0; i < withdrawals.length; ) { if (address(tokens[i]) == address(0)) revert InvalidZeroInput(); // calculate withdrawalRoot bytes32 withdrawalRoot = delegationManager.calculateWithdrawalRoot(withdrawals[i]); // verify withdrawal is not tracked if (queuedWithdrawal[withdrawalRoot]) revert WithdrawalAlreadyTracked(); // verify withdrawal is pending and protocol not double counting if (!delegationManager.pendingWithdrawals(withdrawalRoot)) revert WithdrawalAlreadyCompleted(); // verify LST token is not provided if beaconChainETHStrategy in Withdraw Request if ( address(tokens[i]) != IS_NATIVE && withdrawals[i].strategies[0] == delegationManager.beaconChainETHStrategy() ) revert IncorrectStrategy(); // track queued shares for the token queuedShares[address(tokens[i])] += withdrawals[i].shares[0]; unchecked { ++i; } } } /** * @notice Starts a withdrawal from specified tokens strategies for given amounts * @dev permissioned call (onlyNativeEthRestakeAdmin) * @param tokens list of tokens to withdraw from. For ETH -> 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE * @param tokenAmounts list of token amounts i'th index token in tokens * @return bytes32 withdrawal root */ function queueWithdrawals( IERC20[] calldata tokens, uint256[] calldata tokenAmounts ) external nonReentrant onlyNativeEthRestakeAdmin returns (bytes32) { // record gas spent uint256 gasBefore = gasleft(); if (tokens.length != tokenAmounts.length) revert MismatchedArrayLengths(); IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams = new IDelegationManager.QueuedWithdrawalParams[](1); // set strategies legth for 0th index only queuedWithdrawalParams[0].strategies = new IStrategy[](tokens.length); queuedWithdrawalParams[0].shares = new uint256[](tokens.length); // Save the nonce before starting the withdrawal uint96 nonce = uint96(delegationManager.cumulativeWithdrawalsQueued(address(this))); for (uint256 i; i < tokens.length; ) { if (address(tokens[i]) == IS_NATIVE) { // set beaconChainEthStrategy for ETH queuedWithdrawalParams[0].strategies[i] = eigenPodManager.beaconChainETHStrategy(); // set shares for ETH queuedWithdrawalParams[0].shares[i] = tokenAmounts[i]; } else { if (address(tokenStrategyMapping[tokens[i]]) == address(0)) revert InvalidZeroInput(); // set the strategy of the token queuedWithdrawalParams[0].strategies[i] = tokenStrategyMapping[tokens[i]]; // set the equivalent shares for tokenAmount queuedWithdrawalParams[0].shares[i] = tokenStrategyMapping[tokens[i]] .underlyingToSharesView(tokenAmounts[i]); } // set withdrawer as this contract address queuedWithdrawalParams[0].withdrawer = address(this); // track shares of tokens withdraw for TVL queuedShares[address(tokens[i])] += queuedWithdrawalParams[0].shares[i]; unchecked { ++i; } } // queue withdrawal in EigenLayer bytes32 withdrawalRoot = delegationManager.queueWithdrawals(queuedWithdrawalParams)[0]; // track protocol queued withdrawals queuedWithdrawal[withdrawalRoot] = true; // Emit the withdrawal started event emit WithdrawStarted( withdrawalRoot, address(this), delegateAddress, address(this), nonce, block.number, queuedWithdrawalParams[0].strategies, queuedWithdrawalParams[0].shares ); // update the gas spent for RestakeAdmin _recordGas(gasBefore, NOMINAL_BASE_GAS_SPENT); return withdrawalRoot; } /** * @notice Complete the specified withdrawal, * @dev permissioned call (onlyNativeEthRestakeAdmin) * @param withdrawal Withdrawal struct * @param tokens list of tokens to withdraw * @param middlewareTimesIndex is the index in the operator that the staker who triggered the withdrawal was delegated to's middleware times array */ function completeQueuedWithdrawal( IDelegationManager.Withdrawal calldata withdrawal, IERC20[] calldata tokens, uint256 middlewareTimesIndex ) external nonReentrant onlyNativeEthRestakeAdmin { uint256 gasBefore = gasleft(); if (tokens.length != withdrawal.strategies.length) revert MismatchedArrayLengths(); // complete the queued withdrawal from EigenLayer with receiveAsToken set to true delegationManager.completeQueuedWithdrawal(withdrawal, tokens, middlewareTimesIndex, true); IWithdrawQueue withdrawQueue = restakeManager.depositQueue().withdrawQueue(); for (uint256 i; i < tokens.length; ) { if (address(tokens[i]) == address(0)) revert InvalidZeroInput(); if ( address(tokens[i]) != IS_NATIVE && withdrawal.strategies[i] == delegationManager.beaconChainETHStrategy() ) revert IncorrectStrategy(); // deduct queued shares for tracking TVL queuedShares[address(tokens[i])] -= withdrawal.shares[i]; // check if token is not Native ETH if (address(tokens[i]) != IS_NATIVE) { // Check the withdraw buffer and fill if below buffer target uint256 bufferToFill = withdrawQueue.getWithdrawDeficit(address(tokens[i])); // get balance of this contract uint256 balanceOfToken = tokens[i].balanceOf(address(this)); if (bufferToFill > 0) { bufferToFill = (balanceOfToken <= bufferToFill) ? balanceOfToken : bufferToFill; // update amount to send to the operator Delegator balanceOfToken -= bufferToFill; // safe Approve for depositQueue tokens[i].safeIncreaseAllowance( address(restakeManager.depositQueue()), bufferToFill ); // fill Withdraw Buffer via depositQueue restakeManager.depositQueue().fillERC20withdrawBuffer( address(tokens[i]), bufferToFill ); } // Deposit remaining tokens back to eigenLayer if (balanceOfToken > 0) { _deposit(tokens[i], balanceOfToken); } } unchecked { ++i; } } // emits the Withdraw Completed event with withdrawalRoot emit WithdrawCompleted( delegationManager.calculateWithdrawalRoot(withdrawal), withdrawal.strategies, withdrawal.shares ); // record current spent gas _recordGas(gasBefore, NOMINAL_BASE_GAS_SPENT); } /// @dev Gets the underlying token amount from the amount of shares + queued withdrawal shares function getTokenBalanceFromStrategy(IERC20 token) external view returns (uint256) { return queuedShares[address(token)] == 0 ? tokenStrategyMapping[token].userUnderlyingView(address(this)) : tokenStrategyMapping[token].userUnderlyingView(address(this)) + tokenStrategyMapping[token].sharesToUnderlyingView( queuedShares[address(token)] ); } /// @dev Gets the amount of ETH staked in the EigenLayer function getStakedETHBalance() external view returns (uint256) { // accounts for current podOwner shares + stakedButNotVerified ETH + queued withdraw shares int256 podOwnerShares = eigenPodManager.podOwnerShares(address(this)); return podOwnerShares < 0 ? queuedShares[IS_NATIVE] + stakedButNotVerifiedEth - uint256(-podOwnerShares) : queuedShares[IS_NATIVE] + stakedButNotVerifiedEth + uint256(podOwnerShares); } /// @dev Stake ETH in the EigenLayer /// Only the Restake Manager should call this function function stakeEth( bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot ) external payable onlyRestakeManager { // if validator withdraw credentials is verified if (eigenPod.validatorStatus(pubkey) == IEigenPod.VALIDATOR_STATUS.INACTIVE) { bytes32 validatorPubKeyHash = _calculateValidatorPubkeyHash(pubkey); uint256 validatorCurrentStakedButNotVerifiedEth = validatorStakedButNotVerifiedEth[ validatorPubKeyHash ]; uint256 _stakedButNotVerifiedEth = msg.value; uint256 _validatorStakedButNotVerifiedEth = validatorCurrentStakedButNotVerifiedEth + msg.value; // check if new value addition is greater than MAX_STAKE_BUT_NOT_VERIFIED_AMOUNT if ( validatorCurrentStakedButNotVerifiedEth + msg.value > MAX_STAKE_BUT_NOT_VERIFIED_AMOUNT ) { // stakedButNotVerifiedETH per validator max capped to MAX_STAKE_BUT_NOT_VERIFIED_AMOUNT _stakedButNotVerifiedEth = MAX_STAKE_BUT_NOT_VERIFIED_AMOUNT - validatorCurrentStakedButNotVerifiedEth; // validatorStakedButNotVerifiedEth max cap to MAX_STAKE_BUT_NOT_VERIFIED_AMOUNT per validator _validatorStakedButNotVerifiedEth = MAX_STAKE_BUT_NOT_VERIFIED_AMOUNT; } validatorStakedButNotVerifiedEth[ validatorPubKeyHash ] = _validatorStakedButNotVerifiedEth; // Increment the staked but not verified ETH stakedButNotVerifiedEth += _stakedButNotVerifiedEth; } // Call the stake function in the EigenPodManager eigenPodManager.stake{ value: msg.value }(pubkey, signature, depositDataRoot); } /// @dev Verifies the withdrawal credentials for a withdrawal /// This will allow the EigenPodManager to verify the withdrawal credentials and credit the OD with shares /// Only the native eth restake admin should call this function function verifyWithdrawalCredentials( uint64 oracleTimestamp, BeaconChainProofs.StateRootProof calldata stateRootProof, uint40[] calldata validatorIndices, bytes[] calldata withdrawalCredentialProofs, bytes32[][] calldata validatorFields ) external onlyNativeEthRestakeAdmin { uint256 gasBefore = gasleft(); eigenPod.verifyWithdrawalCredentials( oracleTimestamp, stateRootProof, validatorIndices, withdrawalCredentialProofs, validatorFields ); // Decrement the staked but not verified ETH for (uint256 i = 0; i < validatorFields.length; ) { bytes32 validatorPubkeyHash = validatorFields[i].getPubkeyHash(); // decrement total stakedButNotVerifiedEth by validatorStakedButNotVerifiedEth if (validatorStakedButNotVerifiedEth[validatorPubkeyHash] != 0) { stakedButNotVerifiedEth -= validatorStakedButNotVerifiedEth[validatorPubkeyHash]; } else { // fallback to decrement total stakedButNotVerifiedEth by MAX_STAKE_BUT_NOT_VERIFIED_AMOUNT stakedButNotVerifiedEth -= MAX_STAKE_BUT_NOT_VERIFIED_AMOUNT; } // set validatorStakedButNotVerifiedEth value to 0 validatorStakedButNotVerifiedEth[validatorPubkeyHash] = 0; unchecked { ++i; } } // update the gas spent for RestakeAdmin _recordGas(gasBefore, baseGasAmountSpent); } /** * @notice Verify many Withdrawals and process them in the EigenPod * @dev For each withdrawal (partial or full), verify it in the EigenPod * Only callable by admin. * @param oracleTimestamp . * @param stateRootProof . * @param withdrawalProofs . * @param validatorFieldsProofs . * @param validatorFields . * @param withdrawalFields . */ function verifyAndProcessWithdrawals( uint64 oracleTimestamp, BeaconChainProofs.StateRootProof calldata stateRootProof, BeaconChainProofs.WithdrawalProof[] calldata withdrawalProofs, bytes[] calldata validatorFieldsProofs, bytes32[][] calldata validatorFields, bytes32[][] calldata withdrawalFields ) external onlyNativeEthRestakeAdmin { uint256 gasBefore = gasleft(); eigenPod.verifyAndProcessWithdrawals( oracleTimestamp, stateRootProof, withdrawalProofs, validatorFieldsProofs, validatorFields, withdrawalFields ); // update the gas spent for RestakeAdmin _recordGas(gasBefore, baseGasAmountSpent); } /** * @notice Pull out any ETH in the EigenPod that is not from the beacon chain * @dev Only callable by admin * @param recipient Where to send the ETH * @param amountToWithdraw Amount to pull out */ function withdrawNonBeaconChainETHBalanceWei( address recipient, uint256 amountToWithdraw ) external onlyNativeEthRestakeAdmin { eigenPod.withdrawNonBeaconChainETHBalanceWei(recipient, amountToWithdraw); } /** * @notice Recover tokens accidentally sent to EigenPod * @dev Only callable by admin * @param tokenList . * @param amountsToWithdraw . * @param recipient . */ function recoverTokens( IERC20[] memory tokenList, uint256[] memory amountsToWithdraw, address recipient ) external onlyNativeEthRestakeAdmin { eigenPod.recoverTokens(tokenList, amountsToWithdraw, recipient); } /** * @notice Starts a delayed withdraw of the ETH from the EigenPodManager * @dev Before the eigenpod is verified, we can sweep out any accumulated ETH from the Consensus layer validator rewards * We also want to track the amount in the delayed withdrawal router so we can track the TVL and reward amount accurately */ function startDelayedWithdrawUnstakedETH() external onlyNativeEthRestakeAdmin { // Call the start delayed withdraw function in the EigenPodManager // This will queue up a delayed withdrawal that will be sent back to this address after the timeout eigenPod.withdrawBeforeRestaking(); } /** * @notice Adds the amount of gas spent for an account * @dev Tracks for later redemption from rewards coming from the DWR * @param initialGas . */ function _recordGas(uint256 initialGas, uint256 baseGasAmount) internal { uint256 gasSpent = (initialGas - gasleft() + baseGasAmount) * block.basefee; adminGasSpentInWei[msg.sender] += gasSpent; emit GasSpent(msg.sender, gasSpent); } ///@notice Calculates the pubkey hash of a validator's pubkey as per SSZ spec /// @dev using same calculation as EigenPod _calculateValidatorPubkeyHash function _calculateValidatorPubkeyHash( bytes memory validatorPubkey ) internal pure returns (bytes32) { return sha256(abi.encodePacked(validatorPubkey, bytes16(0))); } /** * @notice Send owed refunds to the admin * @dev . * @return uint256 . */ function _refundGas() internal returns (uint256) { uint256 gasRefund = address(this).balance >= adminGasSpentInWei[tx.origin] ? adminGasSpentInWei[tx.origin] : address(this).balance; bool success = payable(tx.origin).send(gasRefund); if (!success) revert TransferFailed(); // reset gas spent by admin adminGasSpentInWei[tx.origin] -= gasRefund; emit GasRefunded(tx.origin, gasRefund); return gasRefund; } /** * @notice Users should NOT send ETH directly to this contract unless they want to donate to existing ezETH holders. * This is an internal protocol function. * @dev Handle ETH sent to this contract - will get forwarded to the deposit queue for restaking as a protocol reward * @dev If msg.sender is eigenPod then forward ETH to deposit queue without taking cut (i.e. full withdrawal from beacon chain) */ receive() external payable { // check if sender contract is EigenPod. forward full withdrawal eth received if (msg.sender == address(eigenPod)) { restakeManager.depositQueue().forwardFullWithdrawalETH{ value: msg.value }(); } else { // considered as protocol reward uint256 gasRefunded = 0; uint256 remainingAmount = address(this).balance; if (adminGasSpentInWei[tx.origin] > 0) { gasRefunded = _refundGas(); // update the remaining amount remainingAmount -= gasRefunded; // If no funds left, return if (remainingAmount == 0) { return; } } // Forward remaining balance to the deposit queue address destination = address(restakeManager.depositQueue()); (bool success, ) = destination.call{ value: remainingAmount }(""); if (!success) revert TransferFailed(); emit RewardsForwarded(destination, remainingAmount); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.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] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev 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. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ 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. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ 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. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } /** * @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[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.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 * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or 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 { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // 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 v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/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. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ 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]. * * CAUTION: See Security Considerations above. */ 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.9.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.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/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; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ 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)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ 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"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ 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"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation 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). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // 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 cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.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 * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or 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 { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // 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.19; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../EigenLayer/interfaces/IStrategyManager.sol"; import "../EigenLayer/interfaces/IDelegationManager.sol"; import "../EigenLayer/interfaces/IEigenPod.sol"; interface IOperatorDelegator { function getTokenBalanceFromStrategy(IERC20 token) external view returns (uint256); function deposit(IERC20 _token, uint256 _tokenAmount) external returns (uint256 shares); // Note: Withdraws disabled for this release // function startWithdrawal(IERC20 _token, uint256 _tokenAmount) external returns (bytes32); // function completeWithdrawal( // IStrategyManager.DeprecatedStruct_QueuedWithdrawal calldata _withdrawal, // IERC20 _token, // uint256 _middlewareTimesIndex, // address _sendToAddress // ) external; function getStakedETHBalance() external view returns (uint256); function stakeEth( bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot ) external payable; function eigenPod() external view returns (IEigenPod); function pendingUnstakedDelayedWithdrawalAmount() external view returns (uint256); function delegateAddress() external view returns (address); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import "../Permissions/IRoleManager.sol"; import "../EigenLayer/interfaces/IStrategy.sol"; import "../EigenLayer/interfaces/IStrategyManager.sol"; import "../EigenLayer/interfaces/IDelegationManager.sol"; import "../EigenLayer/interfaces/IEigenPod.sol"; import "./IOperatorDelegator.sol"; import "../IRestakeManager.sol"; /// @title OperatorDelegatorStorage /// @dev This contract will hold all local variables for the Contract /// When upgrading the protocol, inherit from this contract on the V2 version and change the /// StorageManager to inherit from the later version. This ensures there are no storage layout /// corruptions when upgrading. abstract contract OperatorDelegatorStorageV1 is IOperatorDelegator { /// @dev reference to the RoleManager contract IRoleManager public roleManager; /// @dev The main strategy manager contract in EigenLayer IStrategyManager public strategyManager; /// @dev the restake manager contract IRestakeManager public restakeManager; /// @dev The mapping of supported token addresses to their respective strategy addresses /// This will control which tokens are supported by the protocol mapping(IERC20 => IStrategy) public tokenStrategyMapping; /// @dev The address to delegate tokens to in EigenLayer address public delegateAddress; /// @dev the delegation manager contract IDelegationManager public delegationManager; /// @dev the EigenLayer EigenPodManager contract IEigenPodManager public eigenPodManager; /// @dev The EigenPod owned by this contract IEigenPod public eigenPod; /// @dev Tracks the balance that was staked to validators but hasn't been restaked to EL yet uint256 public stakedButNotVerifiedEth; } abstract contract OperatorDelegatorStorageV2 is OperatorDelegatorStorageV1 { /// @dev - DEPRECATED - This variable is no longer used uint256 public pendingUnstakedDelayedWithdrawalAmount; } abstract contract OperatorDelegatorStorageV3 is OperatorDelegatorStorageV2 { /// @dev A base tx gas amount for a transaction to be added for redemption later - in gas units uint256 public baseGasAmountSpent; /// @dev A mapping to track how much gas was spent by an address mapping(address => uint256) public adminGasSpentInWei; } abstract contract OperatorDelegatorStorageV4 is OperatorDelegatorStorageV3 { /// @dev mapping of token shares in withdraw queue of EigenLayer mapping(address => uint256) public queuedShares; /// @dev bool mapping to track if withdrawal is already queued by withdrawalRoot mapping(bytes32 => bool) public queuedWithdrawal; /// @dev mapping of validatorStakedButNotVerifiedEth with the key as validatorPubkeyHash mapping(bytes32 => uint256) public validatorStakedButNotVerifiedEth; } /// On the next version of the protocol, if new variables are added, put them in the below /// contract and use this as the inheritance chain. // abstract contract OperatorDelegatorStorageV4 is OperatorDelegatorStorageV3 { // }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import "../Withdraw/IWithdrawQueue.sol"; interface IDepositQueue { function depositETHFromProtocol() external payable; function totalEarned(address tokenAddress) external view returns (uint256); function forwardFullWithdrawalETH() external payable; function withdrawQueue() external view returns (IWithdrawQueue); function fillERC20withdrawBuffer(address _asset, uint256 _amount) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.5.0; /** * @title Interface for the BeaconStateOracle contract. * @author Layr Labs, Inc. * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service */ interface IBeaconChainOracle { /// @notice The block number to state root mapping. function timestampToBlockRoot(uint256 timestamp) external view returns (bytes32); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.5.0; interface IDelayedWithdrawalRouter { // struct used to pack data into a single storage slot struct DelayedWithdrawal { uint224 amount; uint32 blockCreated; } // struct used to store a single users delayedWithdrawal data struct UserDelayedWithdrawals { uint256 delayedWithdrawalsCompleted; DelayedWithdrawal[] delayedWithdrawals; } /// @notice event for delayedWithdrawal creation event DelayedWithdrawalCreated( address podOwner, address recipient, uint256 amount, uint256 index ); /// @notice event for the claiming of delayedWithdrawals event DelayedWithdrawalsClaimed( address recipient, uint256 amountClaimed, uint256 delayedWithdrawalsCompleted ); /// @notice Emitted when the `withdrawalDelayBlocks` variable is modified from `previousValue` to `newValue`. event WithdrawalDelayBlocksSet(uint256 previousValue, uint256 newValue); /** * @notice Creates an delayed withdrawal for `msg.value` to the `recipient`. * @dev Only callable by the `podOwner`'s EigenPod contract. */ function createDelayedWithdrawal(address podOwner, address recipient) external payable; /** * @notice Called in order to withdraw delayed withdrawals made to the `recipient` that have passed the `withdrawalDelayBlocks` period. * @param recipient The address to claim delayedWithdrawals for. * @param maxNumberOfWithdrawalsToClaim Used to limit the maximum number of withdrawals to loop through claiming. */ function claimDelayedWithdrawals( address recipient, uint256 maxNumberOfWithdrawalsToClaim ) external; /** * @notice Called in order to withdraw delayed withdrawals made to the caller that have passed the `withdrawalDelayBlocks` period. * @param maxNumberOfWithdrawalsToClaim Used to limit the maximum number of withdrawals to loop through claiming. */ function claimDelayedWithdrawals(uint256 maxNumberOfWithdrawalsToClaim) external; /// @notice Owner-only function for modifying the value of the `withdrawalDelayBlocks` variable. function setWithdrawalDelayBlocks(uint256 newValue) external; /// @notice Getter function for the mapping `_userWithdrawals` function userWithdrawals(address user) external view returns (UserDelayedWithdrawals memory); /// @notice Getter function to get all delayedWithdrawals of the `user` function getUserDelayedWithdrawals( address user ) external view returns (DelayedWithdrawal[] memory); /// @notice Getter function to get all delayedWithdrawals that are currently claimable by the `user` function getClaimableUserDelayedWithdrawals( address user ) external view returns (DelayedWithdrawal[] memory); /// @notice Getter function for fetching the delayedWithdrawal at the `index`th entry from the `_userWithdrawals[user].delayedWithdrawals` array function userDelayedWithdrawalByIndex( address user, uint256 index ) external view returns (DelayedWithdrawal memory); /// @notice Getter function for fetching the length of the delayedWithdrawals array of a specific user function userWithdrawalsLength(address user) external view returns (uint256); /// @notice Convenience function for checking whether or not the delayedWithdrawal at the `index`th entry from the `_userWithdrawals[user].delayedWithdrawals` array is currently claimable function canClaimDelayedWithdrawal(address user, uint256 index) external view returns (bool); /** * @notice Delay enforced by this contract for completing any delayedWithdrawal. Measured in blocks, and adjustable by this contract's owner, * up to a maximum of `MAX_WITHDRAWAL_DELAY_BLOCKS`. Minimum value is 0 (i.e. no delay enforced). */ function withdrawalDelayBlocks() external view returns (uint256); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.5.0; import "./IStrategy.sol"; import "./ISignatureUtils.sol"; import "./IStrategyManager.sol"; /** * @title DelegationManager * @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 operators to specify parameters related to stakers who delegate to them * - enabling any staker to delegate its stake to the operator of its choice (a given staker can only delegate to a single operator at a time) * - enabling a staker to undelegate its assets from the operator it is delegated to (performed as part of the withdrawal process, initiated through the StrategyManager) */ interface IDelegationManager is ISignatureUtils { // Access to public vars - hack locally function beaconChainETHStrategy() external returns (IStrategy); function pendingWithdrawals(bytes32 withdrawalRoot) external view returns (bool); function getDelegatableShares( address staker ) external view returns (IStrategy[] memory, uint256[] memory); // @notice Struct used for storing information about a single operator who has registered with EigenLayer struct OperatorDetails { // @notice address to receive the rewards that the operator earns via serving applications built on EigenLayer. address earningsReceiver; /** * @notice Address to verify signatures when a staker wishes to delegate to the operator, as well as controlling "forced undelegations". * @dev Signature verification follows these rules: * 1) If this address is left as address(0), then any staker will be free to delegate to the operator, i.e. no signature verification will be performed. * 2) If this address is an EOA (i.e. it has no code), then we follow standard ECDSA signature verification for delegations to the operator. * 3) If this address is a contract (i.e. it has code) then we forward a call to the contract and verify that it returns the correct EIP-1271 "magic value". */ address delegationApprover; /** * @notice A minimum delay -- measured in blocks -- enforced between: * 1) the operator signalling their intent to register for a service, via calling `Slasher.optIntoSlashing` * and * 2) the operator completing registration for the service, via the service ultimately calling `Slasher.recordFirstStakeUpdate` * @dev note that for a specific operator, this value *cannot decrease*, i.e. if the operator wishes to modify their OperatorDetails, * then they are only allowed to either increase this value or keep it the same. */ uint32 stakerOptOutWindowBlocks; } /** * @notice Abstract struct used in calculating an EIP712 signature for a staker to approve that they (the staker themselves) delegate to a specific operator. * @dev Used in computing the `STAKER_DELEGATION_TYPEHASH` and as a reference in the computation of the stakerDigestHash in the `delegateToBySignature` function. */ struct StakerDelegation { // the staker who is delegating address staker; // the operator being delegated to address operator; // the staker's nonce uint256 nonce; // the expiration timestamp (UTC) of the signature uint256 expiry; } /** * @notice Abstract struct used in calculating an EIP712 signature for an operator's delegationApprover to approve that a specific staker delegate to the operator. * @dev Used in computing the `DELEGATION_APPROVAL_TYPEHASH` and as a reference in the computation of the approverDigestHash in the `_delegate` function. */ struct DelegationApproval { // the staker who is delegating address staker; // the operator being delegated to address operator; // the operator's provided salt bytes32 salt; // the expiration timestamp (UTC) of the signature uint256 expiry; } /** * 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. 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 Withdrawal { // The address that originated the Withdrawal address staker; // The address that the staker was delegated to at the time that the Withdrawal was created address delegatedTo; // The address that can complete the Withdrawal + will receive funds when completing the withdrawal address withdrawer; // Nonce used to guarantee that otherwise identical withdrawals have unique hashes uint256 nonce; // Block number when the Withdrawal was created uint32 startBlock; // Array of strategies that the Withdrawal contains IStrategy[] strategies; // Array containing the amount of shares in each Strategy in the `strategies` array uint256[] shares; } struct QueuedWithdrawalParams { // Array of strategies that the QueuedWithdrawal contains IStrategy[] strategies; // Array containing the amount of shares in each Strategy in the `strategies` array uint256[] shares; // The address of the withdrawer address withdrawer; } // @notice Emitted when a new operator registers in EigenLayer and provides their OperatorDetails. event OperatorRegistered(address indexed operator, OperatorDetails operatorDetails); /// @notice Emitted when an operator updates their OperatorDetails to @param newOperatorDetails event OperatorDetailsModified(address indexed operator, OperatorDetails newOperatorDetails); /** * @notice Emitted when @param operator indicates that they are updating their MetadataURI string * @dev Note that these strings are *never stored in storage* and are instead purely emitted in events for off-chain indexing */ event OperatorMetadataURIUpdated(address indexed operator, string metadataURI); /// @notice Emitted whenever an operator's shares are increased for a given strategy. Note that shares is the delta in the operator's shares. event OperatorSharesIncreased( address indexed operator, address staker, IStrategy strategy, uint256 shares ); /// @notice Emitted whenever an operator's shares are decreased for a given strategy. Note that shares is the delta in the operator's shares. event OperatorSharesDecreased( address indexed operator, address staker, IStrategy strategy, uint256 shares ); /// @notice Emitted when @param staker delegates to @param operator. event StakerDelegated(address indexed staker, address indexed operator); /// @notice Emitted when @param staker undelegates from @param operator. event StakerUndelegated(address indexed staker, address indexed operator); /// @notice Emitted when @param staker is undelegated via a call not originating from the staker themself event StakerForceUndelegated(address indexed staker, address indexed operator); /** * @notice Emitted when a new withdrawal is queued. * @param withdrawalRoot Is the hash of the `withdrawal`. * @param withdrawal Is the withdrawal itself. */ event WithdrawalQueued(bytes32 withdrawalRoot, Withdrawal withdrawal); /// @notice Emitted when a queued withdrawal is completed event WithdrawalCompleted(bytes32 withdrawalRoot); /// @notice Emitted when a queued withdrawal is *migrated* from the StrategyManager to the DelegationManager event WithdrawalMigrated(bytes32 oldWithdrawalRoot, bytes32 newWithdrawalRoot); /// @notice Emitted when the `minWithdrawalDelayBlocks` variable is modified from `previousValue` to `newValue`. event MinWithdrawalDelayBlocksSet(uint256 previousValue, uint256 newValue); /// @notice Emitted when the `strategyWithdrawalDelayBlocks` variable is modified from `previousValue` to `newValue`. event StrategyWithdrawalDelayBlocksSet( IStrategy strategy, uint256 previousValue, uint256 newValue ); /** * @notice Registers the caller as an operator in EigenLayer. * @param registeringOperatorDetails is the `OperatorDetails` for the operator. * @param metadataURI is a URI for the operator's metadata, i.e. a link providing more details on the operator. * * @dev Once an operator is registered, they cannot 'deregister' as an operator, and they will forever be considered "delegated to themself". * @dev This function will revert if the caller attempts to set their `earningsReceiver` to address(0). * @dev Note that the `metadataURI` is *never stored * and is only emitted in the `OperatorMetadataURIUpdated` event */ function registerAsOperator( OperatorDetails calldata registeringOperatorDetails, string calldata metadataURI ) external; /** * @notice Updates an operator's stored `OperatorDetails`. * @param newOperatorDetails is the updated `OperatorDetails` for the operator, to replace their current OperatorDetails`. * * @dev The caller must have previously registered as an operator in EigenLayer. * @dev This function will revert if the caller attempts to set their `earningsReceiver` to address(0). */ function modifyOperatorDetails(OperatorDetails calldata newOperatorDetails) external; /** * @notice Called by an operator to emit an `OperatorMetadataURIUpdated` event indicating the information has updated. * @param metadataURI The URI for metadata associated with an operator * @dev Note that the `metadataURI` is *never stored * and is only emitted in the `OperatorMetadataURIUpdated` event */ function updateOperatorMetadataURI(string calldata metadataURI) external; /** * @notice Caller delegates their stake to an operator. * @param operator The account (`msg.sender`) is delegating its assets to for use in serving applications built on EigenLayer. * @param approverSignatureAndExpiry Verifies the operator approves of this delegation * @param approverSalt A unique single use value tied to an individual signature. * @dev The approverSignatureAndExpiry is used in the event that: * 1) the operator's `delegationApprover` address is set to a non-zero value. * AND * 2) neither the operator nor their `delegationApprover` is the `msg.sender`, since in the event that the operator * or their delegationApprover is the `msg.sender`, then approval is assumed. * @dev In the event that `approverSignatureAndExpiry` is not checked, its content is ignored entirely; it's recommended to use an empty input * in this case to save on complexity + gas costs */ function delegateTo( address operator, SignatureWithExpiry memory approverSignatureAndExpiry, bytes32 approverSalt ) external; /** * @notice Caller delegates a staker's stake to an operator with valid signatures from both parties. * @param staker The account delegating stake to an `operator` account * @param operator The account (`staker`) is delegating its assets to for use in serving applications built on EigenLayer. * @param stakerSignatureAndExpiry Signed data from the staker authorizing delegating stake to an operator * @param approverSignatureAndExpiry is a parameter that will be used for verifying that the operator approves of this delegation action in the event that: * @param approverSalt Is a salt used to help guarantee signature uniqueness. Each salt can only be used once by a given approver. * * @dev If `staker` is an EOA, then `stakerSignature` is verified to be a valid ECDSA stakerSignature from `staker`, indicating their intention for this action. * @dev If `staker` is a contract, then `stakerSignature` will be checked according to EIP-1271. * @dev the operator's `delegationApprover` address is set to a non-zero value. * @dev neither the operator nor their `delegationApprover` is the `msg.sender`, since in the event that the operator or their delegationApprover * is the `msg.sender`, then approval is assumed. * @dev This function will revert if the current `block.timestamp` is equal to or exceeds the expiry * @dev In the case that `approverSignatureAndExpiry` is not checked, its content is ignored entirely; it's recommended to use an empty input * in this case to save on complexity + gas costs */ function delegateToBySignature( address staker, address operator, SignatureWithExpiry memory stakerSignatureAndExpiry, SignatureWithExpiry memory approverSignatureAndExpiry, bytes32 approverSalt ) external; /** * @notice Undelegates the staker from the operator who they are delegated to. Puts the staker into the "undelegation limbo" mode of the EigenPodManager * and queues a withdrawal of all of the staker's shares in the StrategyManager (to the staker), if necessary. * @param staker The account to be undelegated. * @return withdrawalRoot The root of the newly queued withdrawal, if a withdrawal was queued. Otherwise just bytes32(0). * * @dev Reverts if the `staker` is also an operator, since operators are not allowed to undelegate from themselves. * @dev Reverts if the caller is not the staker, nor the operator who the staker is delegated to, nor the operator's specified "delegationApprover" * @dev Reverts if the `staker` is already undelegated. */ function undelegate(address staker) external returns (bytes32[] memory withdrawalRoot); /** * Allows a staker to withdraw some shares. Withdrawn shares/strategies are immediately removed * from the staker. If the staker is delegated, withdrawn shares/strategies are also removed from * their operator. * * All withdrawn shares/strategies are placed in a queue and can be fully withdrawn after a delay. */ function queueWithdrawals( QueuedWithdrawalParams[] calldata queuedWithdrawalParams ) external returns (bytes32[] memory); /** * @notice Used to complete the specified `withdrawal`. The caller must match `withdrawal.withdrawer` * @param withdrawal The Withdrawal to complete. * @param tokens Array in which the i-th entry specifies the `token` input to the 'withdraw' function of the i-th Strategy in the `withdrawal.strategies` array. * This input can be provided with zero length if `receiveAsTokens` is set to 'false' (since in that case, this input will be unused) * @param middlewareTimesIndex is the index in the operator that the staker who triggered the withdrawal was delegated to's middleware times array * @param receiveAsTokens If true, the shares specified in the withdrawal will be withdrawn from the specified strategies themselves * and sent to the caller, through calls to `withdrawal.strategies[i].withdraw`. If false, then the shares in the specified strategies * will simply be transferred to the caller directly. * @dev middlewareTimesIndex should be calculated off chain before calling this function by finding the first index that satisfies `slasher.canWithdraw` * @dev beaconChainETHStrategy shares are non-transferrable, so if `receiveAsTokens = false` and `withdrawal.withdrawer != withdrawal.staker`, note that * any beaconChainETHStrategy shares in the `withdrawal` will be _returned to the staker_, rather than transferred to the withdrawer, unlike shares in * any other strategies, which will be transferred to the withdrawer. */ function completeQueuedWithdrawal( Withdrawal calldata withdrawal, IERC20[] calldata tokens, uint256 middlewareTimesIndex, bool receiveAsTokens ) external; /** * @notice Array-ified version of `completeQueuedWithdrawal`. * Used to complete the specified `withdrawals`. The function caller must match `withdrawals[...].withdrawer` * @param withdrawals The Withdrawals to complete. * @param tokens Array of tokens for each Withdrawal. See `completeQueuedWithdrawal` for the usage of a single array. * @param middlewareTimesIndexes One index to reference per Withdrawal. See `completeQueuedWithdrawal` for the usage of a single index. * @param receiveAsTokens Whether or not to complete each withdrawal as tokens. See `completeQueuedWithdrawal` for the usage of a single boolean. * @dev See `completeQueuedWithdrawal` for relevant dev tags */ function completeQueuedWithdrawals( Withdrawal[] calldata withdrawals, IERC20[][] calldata tokens, uint256[] calldata middlewareTimesIndexes, bool[] calldata receiveAsTokens ) external; /** * @notice Increases a staker's delegated share balance in a strategy. * @param staker The address to increase the delegated shares for their operator. * @param strategy The strategy in which to increase the delegated shares. * @param shares The number of shares to increase. * * @dev *If the staker is actively delegated*, then increases the `staker`'s delegated shares in `strategy` by `shares`. Otherwise does nothing. * @dev Callable only by the StrategyManager or EigenPodManager. */ function increaseDelegatedShares(address staker, IStrategy strategy, uint256 shares) external; /** * @notice Decreases a staker's delegated share balance in a strategy. * @param staker The address to increase the delegated shares for their operator. * @param strategy The strategy in which to decrease the delegated shares. * @param shares The number of shares to decrease. * * @dev *If the staker is actively delegated*, then decreases the `staker`'s delegated shares in `strategy` by `shares`. Otherwise does nothing. * @dev Callable only by the StrategyManager or EigenPodManager. */ function decreaseDelegatedShares(address staker, IStrategy strategy, uint256 shares) external; /** * @notice returns the address of the operator that `staker` is delegated to. * @notice Mapping: staker => operator whom the staker is currently delegated to. * @dev Note that returning address(0) indicates that the staker is not actively delegated to any operator. */ function delegatedTo(address staker) external view returns (address); /** * @notice Returns the OperatorDetails struct associated with an `operator`. */ function operatorDetails(address operator) external view returns (OperatorDetails memory); /* * @notice Returns the earnings receiver address for an operator */ function earningsReceiver(address operator) external view returns (address); /** * @notice Returns the delegationApprover account for an operator */ function delegationApprover(address operator) external view returns (address); /** * @notice Returns the stakerOptOutWindowBlocks for an operator */ function stakerOptOutWindowBlocks(address operator) external view returns (uint256); /** * @notice Given array of strategies, returns array of shares for the operator */ function getOperatorShares( address operator, IStrategy[] memory strategies ) external view returns (uint256[] memory); /** * @notice Given a list of strategies, return the minimum number of blocks that must pass to withdraw * from all the inputted strategies. Return value is >= minWithdrawalDelayBlocks as this is the global min withdrawal delay. * @param strategies The strategies to check withdrawal delays for */ function getWithdrawalDelay(IStrategy[] calldata strategies) external view returns (uint256); /** * @notice returns the total number of shares in `strategy` that are delegated to `operator`. * @notice Mapping: operator => strategy => total number of shares in the strategy delegated to the operator. * @dev By design, the following invariant should hold for each Strategy: * (operator's shares in delegation manager) = sum (shares above zero of all stakers delegated to operator) * = sum (delegateable shares of all stakers delegated to the operator) */ function operatorShares(address operator, IStrategy strategy) external view returns (uint256); /** * @notice Returns 'true' if `staker` *is* actively delegated, and 'false' otherwise. */ function isDelegated(address staker) external view returns (bool); /** * @notice Returns true is an operator has previously registered for delegation. */ function isOperator(address operator) external view returns (bool); /// @notice Mapping: staker => number of signed delegation nonces (used in `delegateToBySignature`) from the staker that the contract has already checked function stakerNonce(address staker) external view returns (uint256); /** * @notice Mapping: delegationApprover => 32-byte salt => whether or not the salt has already been used by the delegationApprover. * @dev Salts are used in the `delegateTo` and `delegateToBySignature` functions. Note that these functions only process the delegationApprover's * signature + the provided salt if the operator being delegated to has specified a nonzero address as their `delegationApprover`. */ function delegationApproverSaltIsSpent( address _delegationApprover, bytes32 salt ) external view returns (bool); /** * @notice Minimum delay enforced by this contract for completing queued withdrawals. Measured in blocks, and adjustable by this contract's owner, * up to a maximum of `MAX_WITHDRAWAL_DELAY_BLOCKS`. Minimum value is 0 (i.e. no delay enforced). * Note that strategies each have a separate withdrawal delay, which can be greater than this value. So the minimum number of blocks that must pass * to withdraw a strategy is MAX(minWithdrawalDelayBlocks, strategyWithdrawalDelayBlocks[strategy]) */ function minWithdrawalDelayBlocks() external view returns (uint256); /** * @notice Minimum delay enforced by this contract per Strategy for completing queued withdrawals. Measured in blocks, and adjustable by this contract's owner, * up to a maximum of `MAX_WITHDRAWAL_DELAY_BLOCKS`. Minimum value is 0 (i.e. no delay enforced). */ function strategyWithdrawalDelayBlocks(IStrategy strategy) external view returns (uint256); /** * @notice Calculates the digestHash for a `staker` to sign to delegate to an `operator` * @param staker The signing staker * @param operator The operator who is being delegated to * @param expiry The desired expiry time of the staker's signature */ function calculateCurrentStakerDelegationDigestHash( address staker, address operator, uint256 expiry ) external view returns (bytes32); /** * @notice Calculates the digest hash to be signed and used in the `delegateToBySignature` function * @param staker The signing staker * @param _stakerNonce The nonce of the staker. In practice we use the staker's current nonce, stored at `stakerNonce[staker]` * @param operator The operator who is being delegated to * @param expiry The desired expiry time of the staker's signature */ function calculateStakerDelegationDigestHash( address staker, uint256 _stakerNonce, address operator, uint256 expiry ) external view returns (bytes32); /** * @notice Calculates the digest hash to be signed by the operator's delegationApprove and used in the `delegateTo` and `delegateToBySignature` functions. * @param staker The account delegating their stake * @param operator The account receiving delegated stake * @param _delegationApprover the operator's `delegationApprover` who will be signing the delegationHash (in general) * @param approverSalt A unique and single use value associated with the approver signature. * @param expiry Time after which the approver's signature becomes invalid */ function calculateDelegationApprovalDigestHash( address staker, address operator, address _delegationApprover, bytes32 approverSalt, uint256 expiry ) external view returns (bytes32); /// @notice The EIP-712 typehash for the contract's domain function DOMAIN_TYPEHASH() external view returns (bytes32); /// @notice The EIP-712 typehash for the StakerDelegation struct used by the contract function STAKER_DELEGATION_TYPEHASH() external view returns (bytes32); /// @notice The EIP-712 typehash for the DelegationApproval struct used by the contract function DELEGATION_APPROVAL_TYPEHASH() external view returns (bytes32); /** * @notice Getter function for the current EIP-712 domain separator for this contract. * * @dev The domain separator will change in the event of a fork that changes the ChainID. * @dev By introducing a domain separator the DApp developers are guaranteed that there can be no signature collision. * for more detailed information please read EIP-712. */ function domainSeparator() external view returns (bytes32); /// @notice Mapping: staker => cumulative number of queued withdrawals they have ever initiated. /// @dev This only increments (doesn't decrement), and is used to help ensure that otherwise identical withdrawals have unique hashes. function cumulativeWithdrawalsQueued(address staker) external view returns (uint256); /// @notice Returns the keccak256 hash of `withdrawal`. function calculateWithdrawalRoot(Withdrawal memory withdrawal) external pure returns (bytes32); function migrateQueuedWithdrawals( IStrategyManager.DeprecatedStruct_QueuedWithdrawal[] memory withdrawalsToQueue ) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.5.0; import "../libraries/BeaconChainProofs.sol"; import "./IEigenPodManager.sol"; import "./IBeaconChainOracle.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./IDelayedWithdrawalRouter.sol"; /** * @title The implementation contract used for restaking beacon chain ETH on EigenLayer * @author Layr Labs, Inc. * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service * @notice The main functionalities are: * - creating new ETH validators with their withdrawal credentials pointed to this contract * - proving from beacon chain state roots that withdrawal credentials are pointed to this contract * - proving from beacon chain state roots the balances of ETH validators with their withdrawal credentials * pointed to this contract * - updating aggregate balances in the EigenPodManager * - withdrawing eth when withdrawals are initiated * @dev Note that all beacon chain balances are stored as gwei within the beacon chain datastructures. We choose * to account balances in terms of gwei in the EigenPod contract and convert to wei when making calls to other contracts */ interface IEigenPod { // Hack to allow the external visibility of the public variable for default getter in EigenPod function delayedWithdrawalRouter() external returns (IDelayedWithdrawalRouter); enum VALIDATOR_STATUS { INACTIVE, // doesnt exist ACTIVE, // staked on ethpos and withdrawal credentials are pointed to the EigenPod WITHDRAWN // withdrawn from the Beacon Chain } struct ValidatorInfo { // index of the validator in the beacon chain uint64 validatorIndex; // amount of beacon chain ETH restaked on EigenLayer in gwei uint64 restakedBalanceGwei; //timestamp of the validator's most recent balance update uint64 mostRecentBalanceUpdateTimestamp; // status of the validator VALIDATOR_STATUS status; } /** * @notice struct used to store amounts related to proven withdrawals in memory. Used to help * manage stack depth and optimize the number of external calls, when batching withdrawal operations. */ struct VerifiedWithdrawal { // amount to send to a podOwner from a proven withdrawal uint256 amountToSendGwei; // difference in shares to be recorded in the eigenPodManager, as a result of the withdrawal int256 sharesDeltaGwei; } enum PARTIAL_WITHDRAWAL_CLAIM_STATUS { REDEEMED, PENDING, FAILED } /// @notice Emitted when an ETH validator stakes via this eigenPod event EigenPodStaked(bytes pubkey); /// @notice Emitted when an ETH validator's withdrawal credentials are successfully verified to be pointed to this eigenPod event ValidatorRestaked(uint40 validatorIndex); /// @notice Emitted when an ETH validator's balance is proven to be updated. Here newValidatorBalanceGwei // is the validator's balance that is credited on EigenLayer. event ValidatorBalanceUpdated( uint40 validatorIndex, uint64 balanceTimestamp, uint64 newValidatorBalanceGwei ); /// @notice Emitted when an ETH validator is prove to have withdrawn from the beacon chain event FullWithdrawalRedeemed( uint40 validatorIndex, uint64 withdrawalTimestamp, address indexed recipient, uint64 withdrawalAmountGwei ); /// @notice Emitted when a partial withdrawal claim is successfully redeemed event PartialWithdrawalRedeemed( uint40 validatorIndex, uint64 withdrawalTimestamp, address indexed recipient, uint64 partialWithdrawalAmountGwei ); /// @notice Emitted when restaked beacon chain ETH is withdrawn from the eigenPod. event RestakedBeaconChainETHWithdrawn(address indexed recipient, uint256 amount); /// @notice Emitted when podOwner enables restaking event RestakingActivated(address indexed podOwner); /// @notice Emitted when ETH is received via the `receive` fallback event NonBeaconChainETHReceived(uint256 amountReceived); /// @notice Emitted when ETH that was previously received via the `receive` fallback is withdrawn event NonBeaconChainETHWithdrawn(address indexed recipient, uint256 amountWithdrawn); /// @notice The max amount of eth, in gwei, that can be restaked per validator function MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR() external view returns (uint64); /// @notice the amount of execution layer ETH in this contract that is staked in EigenLayer (i.e. withdrawn from beaconchain but not EigenLayer), function withdrawableRestakedExecutionLayerGwei() external view returns (uint64); /// @notice any ETH deposited into the EigenPod contract via the `receive` fallback function function nonBeaconChainETHBalanceWei() external view returns (uint256); /// @notice Used to initialize the pointers to contracts crucial to the pod's functionality, in beacon proxy construction from EigenPodManager function initialize(address owner) external; /// @notice Called by EigenPodManager when the owner wants to create another ETH validator. function stake( bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot ) external payable; /** * @notice Transfers `amountWei` in ether from this contract to the specified `recipient` address * @notice Called by EigenPodManager to withdrawBeaconChainETH that has been added to the EigenPod's balance due to a withdrawal from the beacon chain. * @dev The podOwner must have already proved sufficient withdrawals, so that this pod's `withdrawableRestakedExecutionLayerGwei` exceeds the * `amountWei` input (when converted to GWEI). * @dev Reverts if `amountWei` is not a whole Gwei amount */ function withdrawRestakedBeaconChainETH(address recipient, uint256 amount) external; /// @notice The single EigenPodManager for EigenLayer function eigenPodManager() external view returns (IEigenPodManager); /// @notice The owner of this EigenPod function podOwner() external view returns (address); /// @notice an indicator of whether or not the podOwner has ever "fully restaked" by successfully calling `verifyCorrectWithdrawalCredentials`. function hasRestaked() external view returns (bool); /** * @notice The latest timestamp at which the pod owner withdrew the balance of the pod, via calling `withdrawBeforeRestaking`. * @dev This variable is only updated when the `withdrawBeforeRestaking` function is called, which can only occur before `hasRestaked` is set to true for this pod. * Proofs for this pod are only valid against Beacon Chain state roots corresponding to timestamps after the stored `mostRecentWithdrawalTimestamp`. */ function mostRecentWithdrawalTimestamp() external view returns (uint64); /// @notice Returns the validatorInfo struct for the provided pubkeyHash function validatorPubkeyHashToInfo( bytes32 validatorPubkeyHash ) external view returns (ValidatorInfo memory); /// @notice Returns the validatorInfo struct for the provided pubkey function validatorPubkeyToInfo( bytes calldata validatorPubkey ) external view returns (ValidatorInfo memory); ///@notice mapping that tracks proven withdrawals function provenWithdrawal( bytes32 validatorPubkeyHash, uint64 slot ) external view returns (bool); /// @notice This returns the status of a given validator function validatorStatus(bytes32 pubkeyHash) external view returns (VALIDATOR_STATUS); /// @notice This returns the status of a given validator pubkey function validatorStatus( bytes calldata validatorPubkey ) external view returns (VALIDATOR_STATUS); /** * @notice This function verifies that the withdrawal credentials of validator(s) owned by the podOwner are pointed to * this contract. It also verifies the effective balance of the validator. It verifies the provided proof of the ETH validator against the beacon chain state * root, marks the validator as 'active' in EigenLayer, and credits the restaked ETH in Eigenlayer. * @param oracleTimestamp is the Beacon Chain timestamp whose state root the `proof` will be proven against. * @param validatorIndices is the list of indices of the validators being proven, refer to consensus specs * @param withdrawalCredentialProofs is an array of proofs, where each proof proves each ETH validator's balance and withdrawal credentials * against a beacon chain state root * @param validatorFields are the fields of the "Validator Container", refer to consensus specs * for details: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator */ function verifyWithdrawalCredentials( uint64 oracleTimestamp, BeaconChainProofs.StateRootProof calldata stateRootProof, uint40[] calldata validatorIndices, bytes[] calldata withdrawalCredentialProofs, bytes32[][] calldata validatorFields ) external; /** * @notice This function records an update (either increase or decrease) in the pod's balance in the StrategyManager. It also verifies a merkle proof of the validator's current beacon chain balance. * @param oracleTimestamp The oracleTimestamp whose state root the `proof` will be proven against. * Must be within `VERIFY_BALANCE_UPDATE_WINDOW_SECONDS` of the current block. * @param validatorIndices is the list of indices of the validators being proven, refer to consensus specs * @param validatorFieldsProofs proofs against the `beaconStateRoot` for each validator in `validatorFields` * @param validatorFields are the fields of the "Validator Container", refer to consensus specs * @dev For more details on the Beacon Chain spec, see: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator */ function verifyBalanceUpdates( uint64 oracleTimestamp, uint40[] calldata validatorIndices, BeaconChainProofs.StateRootProof calldata stateRootProof, bytes[] calldata validatorFieldsProofs, bytes32[][] calldata validatorFields ) external; /** * @notice This function records full and partial withdrawals on behalf of one of the Ethereum validators for this EigenPod * @param oracleTimestamp is the timestamp of the oracle slot that the withdrawal is being proven against * @param withdrawalProofs is the information needed to check the veracity of the block numbers and withdrawals being proven * @param validatorFieldsProofs is the proof of the validator's fields' in the validator tree * @param withdrawalFields are the fields of the withdrawals being proven * @param validatorFields are the fields of the validators being proven */ function verifyAndProcessWithdrawals( uint64 oracleTimestamp, BeaconChainProofs.StateRootProof calldata stateRootProof, BeaconChainProofs.WithdrawalProof[] calldata withdrawalProofs, bytes[] calldata validatorFieldsProofs, bytes32[][] calldata validatorFields, bytes32[][] calldata withdrawalFields ) external; /** * @notice Called by the pod owner to activate restaking by withdrawing * all existing ETH from the pod and preventing further withdrawals via * "withdrawBeforeRestaking()" */ function activateRestaking() external; /// @notice Called by the pod owner to withdraw the balance of the pod when `hasRestaked` is set to false function withdrawBeforeRestaking() external; /// @notice Called by the pod owner to withdraw the nonBeaconChainETHBalanceWei function withdrawNonBeaconChainETHBalanceWei( address recipient, uint256 amountToWithdraw ) external; /// @notice called by owner of a pod to remove any ERC20s deposited in the pod function recoverTokens( IERC20[] memory tokenList, uint256[] memory amountsToWithdraw, address recipient ) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.5.0; import "@openzeppelin/contracts/proxy/beacon/IBeacon.sol"; import "./IETHPOSDeposit.sol"; import "./IStrategyManager.sol"; import "./IEigenPod.sol"; import "./IBeaconChainOracle.sol"; import "./IPausable.sol"; import "./ISlasher.sol"; import "./IStrategy.sol"; /** * @title Interface for factory that creates and manages solo staking pods that have their withdrawal credentials pointed to EigenLayer. * @author Layr Labs, Inc. * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service */ interface IEigenPodManager is IPausable { /// @notice Emitted to notify the update of the beaconChainOracle address event BeaconOracleUpdated(address indexed newOracleAddress); /// @notice Emitted to notify the deployment of an EigenPod event PodDeployed(address indexed eigenPod, address indexed podOwner); /// @notice Emitted to notify a deposit of beacon chain ETH recorded in the strategy manager event BeaconChainETHDeposited(address indexed podOwner, uint256 amount); /// @notice Emitted when the balance of an EigenPod is updated event PodSharesUpdated(address indexed podOwner, int256 sharesDelta); /// @notice Emitted when a withdrawal of beacon chain ETH is completed event BeaconChainETHWithdrawalCompleted( address indexed podOwner, uint256 shares, uint96 nonce, address delegatedAddress, address withdrawer, bytes32 withdrawalRoot ); event DenebForkTimestampUpdated(uint64 newValue); /** * @notice Creates an EigenPod for the sender. * @dev Function will revert if the `msg.sender` already has an EigenPod. * @dev Returns EigenPod address */ function createPod() external returns (address); /** * @notice Stakes for a new beacon chain validator on the sender's EigenPod. * Also creates an EigenPod for the sender if they don't have one already. * @param pubkey The 48 bytes public key of the beacon chain validator. * @param signature The validator's signature of the deposit data. * @param depositDataRoot The root/hash of the deposit data for the validator's deposit. */ function stake( bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot ) external payable; /** * @notice Changes the `podOwner`'s shares by `sharesDelta` and performs a call to the DelegationManager * to ensure that delegated shares are also tracked correctly * @param podOwner is the pod owner whose balance is being updated. * @param sharesDelta is the change in podOwner's beaconChainETHStrategy shares * @dev Callable only by the podOwner's EigenPod contract. * @dev Reverts if `sharesDelta` is not a whole Gwei amount */ function recordBeaconChainETHBalanceUpdate(address podOwner, int256 sharesDelta) external; /** * @notice Updates the oracle contract that provides the beacon chain state root * @param newBeaconChainOracle is the new oracle contract being pointed to * @dev Callable only by the owner of this contract (i.e. governance) */ function updateBeaconChainOracle(IBeaconChainOracle newBeaconChainOracle) external; /// @notice Returns the address of the `podOwner`'s EigenPod if it has been deployed. function ownerToPod(address podOwner) external view returns (IEigenPod); /// @notice Returns the address of the `podOwner`'s EigenPod (whether it is deployed yet or not). function getPod(address podOwner) external view returns (IEigenPod); /// @notice The ETH2 Deposit Contract function ethPOS() external view returns (IETHPOSDeposit); /// @notice Beacon proxy to which the EigenPods point function eigenPodBeacon() external view returns (IBeacon); /// @notice Oracle contract that provides updates to the beacon chain's state function beaconChainOracle() external view returns (IBeaconChainOracle); /// @notice Returns the beacon block root at `timestamp`. Reverts if the Beacon block root at `timestamp` has not yet been finalized. function getBlockRootAtTimestamp(uint64 timestamp) external view returns (bytes32); /// @notice EigenLayer's StrategyManager contract function strategyManager() external view returns (IStrategyManager); /// @notice EigenLayer's Slasher contract function slasher() external view returns (ISlasher); /// @notice Returns 'true' if the `podOwner` has created an EigenPod, and 'false' otherwise. function hasPod(address podOwner) external view returns (bool); /// @notice Returns the number of EigenPods that have been created function numPods() external view returns (uint256); /** * @notice Mapping from Pod owner owner to the number of shares they have in the virtual beacon chain ETH strategy. * @dev The share amount can become negative. This is necessary to accommodate the fact that a pod owner's virtual beacon chain ETH shares can * decrease between the pod owner queuing and completing a withdrawal. * When the pod owner's shares would otherwise increase, this "deficit" is decreased first _instead_. * Likewise, when a withdrawal is completed, this "deficit" is decreased and the withdrawal amount is decreased; We can think of this * as the withdrawal "paying off the deficit". */ function podOwnerShares(address podOwner) external view returns (int256); /// @notice returns canonical, virtual beaconChainETH strategy function beaconChainETHStrategy() external view returns (IStrategy); /** * @notice Used by the DelegationManager to remove a pod owner's shares while they're in the withdrawal queue. * Simply decreases the `podOwner`'s shares by `shares`, down to a minimum of zero. * @dev This function reverts if it would result in `podOwnerShares[podOwner]` being less than zero, i.e. it is forbidden for this function to * result in the `podOwner` incurring a "share deficit". This behavior prevents a Staker from queuing a withdrawal which improperly removes excessive * shares from the operator to whom the staker is delegated. * @dev Reverts if `shares` is not a whole Gwei amount */ function removeShares(address podOwner, uint256 shares) external; /** * @notice Increases the `podOwner`'s shares by `shares`, paying off deficit if possible. * Used by the DelegationManager to award a pod owner shares on exiting the withdrawal queue * @dev Returns the number of shares added to `podOwnerShares[podOwner]` above zero, which will be less than the `shares` input * in the event that the podOwner has an existing shares deficit (i.e. `podOwnerShares[podOwner]` starts below zero) * @dev Reverts if `shares` is not a whole Gwei amount */ function addShares(address podOwner, uint256 shares) external returns (uint256); /** * @notice Used by the DelegationManager to complete a withdrawal, sending tokens to some destination address * @dev Prioritizes decreasing the podOwner's share deficit, if they have one * @dev Reverts if `shares` is not a whole Gwei amount */ function withdrawSharesAsTokens(address podOwner, address destination, uint256 shares) external; /** * @notice the deneb hard fork timestamp used to determine which proof path to use for proving a withdrawal */ function denebForkTimestamp() external view returns (uint64); /** * setting the deneb hard fork timestamp by the eigenPodManager owner * @dev this function is designed to be called twice. Once, it is set to type(uint64).max * prior to the actual deneb fork timestamp being set, and then the second time it is set * to the actual deneb fork timestamp. */ function setDenebForkTimestamp(uint64 newDenebForkTimestamp) external; }
// ┏━━━┓━┏┓━┏┓━━┏━━━┓━━┏━━━┓━━━━┏━━━┓━━━━━━━━━━━━━━━━━━━┏┓━━━━━┏━━━┓━━━━━━━━━┏┓━━━━━━━━━━━━━━┏┓━ // ┃┏━━┛┏┛┗┓┃┃━━┃┏━┓┃━━┃┏━┓┃━━━━┗┓┏┓┃━━━━━━━━━━━━━━━━━━┏┛┗┓━━━━┃┏━┓┃━━━━━━━━┏┛┗┓━━━━━━━━━━━━┏┛┗┓ // ┃┗━━┓┗┓┏┛┃┗━┓┗┛┏┛┃━━┃┃━┃┃━━━━━┃┃┃┃┏━━┓┏━━┓┏━━┓┏━━┓┏┓┗┓┏┛━━━━┃┃━┗┛┏━━┓┏━┓━┗┓┏┛┏━┓┏━━┓━┏━━┓┗┓┏┛ // ┃┏━━┛━┃┃━┃┏┓┃┏━┛┏┛━━┃┃━┃┃━━━━━┃┃┃┃┃┏┓┃┃┏┓┃┃┏┓┃┃━━┫┣┫━┃┃━━━━━┃┃━┏┓┃┏┓┃┃┏┓┓━┃┃━┃┏┛┗━┓┃━┃┏━┛━┃┃━ // ┃┗━━┓━┃┗┓┃┃┃┃┃┃┗━┓┏┓┃┗━┛┃━━━━┏┛┗┛┃┃┃━┫┃┗┛┃┃┗┛┃┣━━┃┃┃━┃┗┓━━━━┃┗━┛┃┃┗┛┃┃┃┃┃━┃┗┓┃┃━┃┗┛┗┓┃┗━┓━┃┗┓ // ┗━━━┛━┗━┛┗┛┗┛┗━━━┛┗┛┗━━━┛━━━━┗━━━┛┗━━┛┃┏━┛┗━━┛┗━━┛┗┛━┗━┛━━━━┗━━━┛┗━━┛┗┛┗┛━┗━┛┗┛━┗━━━┛┗━━┛━┗━┛ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┗┛━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // SPDX-License-Identifier: CC0-1.0 pragma solidity >=0.5.0; // This interface is designed to be compatible with the Vyper version. /// @notice This is the Ethereum 2.0 deposit contract interface. /// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs interface IETHPOSDeposit { /// @notice A processed deposit event. event DepositEvent( bytes pubkey, bytes withdrawal_credentials, bytes amount, bytes signature, bytes index ); /// @notice Submit a Phase 0 DepositData object. /// @param pubkey A BLS12-381 public key. /// @param withdrawal_credentials Commitment to a public key for withdrawals. /// @param signature A BLS12-381 signature. /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object. /// Used as a protection against malformed input. function deposit( bytes calldata pubkey, bytes calldata withdrawal_credentials, bytes calldata signature, bytes32 deposit_data_root ) external payable; /// @notice Query the current deposit root hash. /// @return The deposit root hash. function get_deposit_root() external view returns (bytes32); /// @notice Query the current deposit count. /// @return The deposit count encoded as a little endian 64-bit number. function get_deposit_count() external view returns (bytes memory); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.5.0; 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 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 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: BUSL-1.1 pragma solidity >=0.5.0; /** * @title Interface for the `PauserRegistry` contract. * @author Layr Labs, Inc. * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service */ interface IPauserRegistry { event PauserStatusChanged(address pauser, bool canPause); event UnpauserChanged(address previousUnpauser, address newUnpauser); /// @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); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.5.0; /** * @title The interface for common signature utilities. * @author Layr Labs, Inc. * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service */ interface ISignatureUtils { // @notice Struct that bundles together a signature and an expiration time for the signature. Used primarily for stack management. struct SignatureWithExpiry { // the signature itself, formatted as a single bytes object bytes signature; // the expiration timestamp (UTC) of the signature uint256 expiry; } // @notice Struct that bundles together a signature, a salt for uniqueness, and an expiration time for the signature. Used primarily for stack management. struct SignatureWithSaltAndExpiry { // the signature itself, formatted as a single bytes object bytes signature; // the salt used to generate the signature bytes32 salt; // the expiration timestamp (UTC) of the signature uint256 expiry; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.5.0; import "./IStrategyManager.sol"; import "./IDelegationManager.sol"; /** * @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 at which the contract begins being able to finalize the operator's registration with the service via calling `recordFirstStakeUpdate` uint32 registrationMayBeginAtBlock; // 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 Emitted when a middleware times is added to `operator`'s array. event MiddlewareTimesAdded( address operator, uint256 index, uint32 stalestUpdateBlock, uint32 latestServeUntilBlock ); /// @notice Emitted when `operator` begins to allow `contractAddress` to slash them. event OptedIntoSlashing(address indexed operator, address indexed contractAddress); /// @notice Emitted when `contractAddress` signals that it will no longer be able to slash `operator` after the `contractCanSlashOperatorUntilBlock`. event SlashingAbilityRevoked( address indexed operator, address indexed contractAddress, uint32 contractCanSlashOperatorUntilBlock ); /** * @notice Emitted when `slashingContract` 'freezes' the `slashedOperator`. * @dev The `slashingContract` must have permission to slash the `slashedOperator`, i.e. `canSlash(slasherOperator, slashingContract)` must return 'true'. */ event OperatorFrozen(address indexed slashedOperator, address indexed slashingContract); /// @notice Emitted when `previouslySlashedAddress` is 'unfrozen', allowing them to again move deposited funds within EigenLayer. event FrozenStatusReset(address indexed previouslySlashedAddress); /** * @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 The StrategyManager contract of EigenLayer function strategyManager() external view returns (IStrategyManager); /// @notice The DelegationManager contract of EigenLayer function delegation() external view returns (IDelegationManager); /** * @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 getMiddlewareTimesIndexStalestUpdateBlock( 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.5.0; 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 `recipient`'s address * @param recipient 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 recipient, 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 convenience function for fetching the current total shares of `user` in this strategy, by * querying the `strategyManager` contract */ function shares(address user) external view 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.5.0; import "./IStrategy.sol"; import "./ISlasher.sol"; import "./IDelegationManager.sol"; import "./IEigenPodManager.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 { // Access to public vars - hack locally function stakerStrategyList(address staker, uint256 index) external view returns (IStrategy); function strategyIsWhitelistedForDeposit(IStrategy _strategy) external view returns (bool); /** * @notice Emitted when a new deposit occurs on behalf of `staker`. * @param staker Is the staker who is depositing funds into EigenLayer. * @param strategy Is the strategy that `staker` has deposited into. * @param token Is the token that `staker` deposited. * @param shares Is the number of new shares `staker` has been granted in `strategy`. */ event Deposit(address staker, IERC20 token, IStrategy strategy, uint256 shares); /// @notice Emitted when `thirdPartyTransfersForbidden` is updated for a strategy and value by the owner event UpdatedThirdPartyTransfersForbidden(IStrategy strategy, bool value); /// @notice Emitted when the `strategyWhitelister` is changed event StrategyWhitelisterChanged(address previousAddress, address newAddress); /// @notice Emitted when a strategy is added to the approved list of strategies for deposit event StrategyAddedToDepositWhitelist(IStrategy strategy); /// @notice Emitted when a strategy is removed from the approved list of strategies for deposit event StrategyRemovedFromDepositWhitelist(IStrategy strategy); /** * @notice Deposits `amount` of `token` into the specified `strategy`, with the resultant shares credited to `msg.sender` * @param strategy is the specified strategy where deposit is to be made, * @param token is the denomination in which the deposit is to be made, * @param amount is the amount of token to be deposited in the strategy by the staker * @return shares The amount of new shares in the `strategy` created as part of the action. * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf. * @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 Used for depositing an asset into the specified strategy with the resultant shares credited to `staker`, * who must sign off on the action. * Note that the assets are transferred out/from the `msg.sender`, not from the `staker`; this function is explicitly designed * purely to help one address deposit 'for' another. * @param strategy is the specified strategy where deposit is to be made, * @param token is the denomination in which the deposit is to be made, * @param amount is the amount of token to be deposited in the strategy by the staker * @param staker the staker that the deposited assets will be credited to * @param expiry the timestamp at which the signature expires * @param signature is a valid signature from the `staker`. either an ECDSA signature if the `staker` is an EOA, or data to forward * following EIP-1271 if the `staker` is a contract * @return shares The amount of new shares in the `strategy` created as part of the action. * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf. * @dev A signature is required for this function to eliminate the possibility of griefing attacks, specifically those * targeting stakers who may be attempting to undelegate. * @dev Cannot be called if thirdPartyTransfersForbidden is set to true for this strategy * * WARNING: Depositing tokens that allow reentrancy (eg. ERC-777) into a strategy is not recommended. This can lead to attack vectors * where the token balance and corresponding strategy shares are not in sync upon reentrancy */ function depositIntoStrategyWithSignature( IStrategy strategy, IERC20 token, uint256 amount, address staker, uint256 expiry, bytes memory signature ) external returns (uint256 shares); /// @notice Used by the DelegationManager to remove a Staker's shares from a particular strategy when entering the withdrawal queue function removeShares(address staker, IStrategy strategy, uint256 shares) external; /// @notice Used by the DelegationManager to award a Staker some shares that have passed through the withdrawal queue function addShares(address staker, IERC20 token, IStrategy strategy, uint256 shares) external; /// @notice Used by the DelegationManager to convert withdrawn shares to tokens and send them to a recipient function withdrawSharesAsTokens( address recipient, IStrategy strategy, uint256 shares, IERC20 token ) external; /// @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 staker's deposits and corresponding shares * @return (staker's strategies, shares in these strategies) */ function getDeposits( address staker ) 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 Owner-only function that adds the provided Strategies to the 'whitelist' of strategies that stakers can deposit into * @param strategiesToWhitelist Strategies that will be added to the `strategyIsWhitelistedForDeposit` mapping (if they aren't in it already) * @param thirdPartyTransfersForbiddenValues bool values to set `thirdPartyTransfersForbidden` to for each strategy */ function addStrategiesToDepositWhitelist( IStrategy[] calldata strategiesToWhitelist, bool[] calldata thirdPartyTransfersForbiddenValues ) 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 EigenPodManager contract of EigenLayer function eigenPodManager() external view returns (IEigenPodManager); /// @notice Returns the address of the `strategyWhitelister` function strategyWhitelister() external view returns (address); /** * @notice Returns bool for whether or not `strategy` enables credit transfers. i.e enabling * depositIntoStrategyWithSignature calls or queueing withdrawals to a different address than the staker. */ function thirdPartyTransfersForbidden(IStrategy strategy) external view returns (bool); // LIMITED BACKWARDS-COMPATIBILITY FOR DEPRECATED FUNCTIONALITY // packed struct for queued withdrawals; helps deal with stack-too-deep errors struct DeprecatedStruct_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 DeprecatedStruct_QueuedWithdrawal { IStrategy[] strategies; uint256[] shares; address staker; DeprecatedStruct_WithdrawerAndNonce withdrawerAndNonce; uint32 withdrawalStartBlock; address delegatedAddress; } function migrateQueuedWithdrawal( DeprecatedStruct_QueuedWithdrawal memory queuedWithdrawal ) external returns (bool, bytes32); function calculateWithdrawalRoot( DeprecatedStruct_QueuedWithdrawal memory queuedWithdrawal ) external pure returns (bytes32); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.19; import "./Merkle.sol"; import "../libraries/Endian.sol"; //Utility library for parsing and PHASE0 beacon chain block headers //SSZ Spec: https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#merkleization //BeaconBlockHeader Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader //BeaconState Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconstate library BeaconChainProofs { // constants are the number of fields and the heights of the different merkle trees used in merkleizing beacon chain containers uint256 internal constant BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT = 3; uint256 internal constant BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT = 4; uint256 internal constant BEACON_STATE_FIELD_TREE_HEIGHT = 5; uint256 internal constant VALIDATOR_FIELD_TREE_HEIGHT = 3; //Note: changed in the deneb hard fork from 4->5 uint256 internal constant EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_DENEB = 5; uint256 internal constant EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_CAPELLA = 4; // SLOTS_PER_HISTORICAL_ROOT = 2**13, so tree height is 13 uint256 internal constant BLOCK_ROOTS_TREE_HEIGHT = 13; //HISTORICAL_ROOTS_LIMIT = 2**24, so tree height is 24 uint256 internal constant HISTORICAL_SUMMARIES_TREE_HEIGHT = 24; //Index of block_summary_root in historical_summary container uint256 internal constant BLOCK_SUMMARY_ROOT_INDEX = 0; // tree height for hash tree of an individual withdrawal container uint256 internal constant WITHDRAWAL_FIELD_TREE_HEIGHT = 2; uint256 internal constant VALIDATOR_TREE_HEIGHT = 40; // MAX_WITHDRAWALS_PER_PAYLOAD = 2**4, making tree height = 4 uint256 internal constant WITHDRAWALS_TREE_HEIGHT = 4; //in beacon block body https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#beaconblockbody uint256 internal constant EXECUTION_PAYLOAD_INDEX = 9; // in beacon block header https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader uint256 internal constant SLOT_INDEX = 0; uint256 internal constant STATE_ROOT_INDEX = 3; uint256 internal constant BODY_ROOT_INDEX = 4; // in beacon state https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#beaconstate uint256 internal constant VALIDATOR_TREE_ROOT_INDEX = 11; uint256 internal constant HISTORICAL_SUMMARIES_INDEX = 27; // in validator https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator uint256 internal constant VALIDATOR_PUBKEY_INDEX = 0; uint256 internal constant VALIDATOR_WITHDRAWAL_CREDENTIALS_INDEX = 1; uint256 internal constant VALIDATOR_BALANCE_INDEX = 2; uint256 internal constant VALIDATOR_WITHDRAWABLE_EPOCH_INDEX = 7; // in execution payload header uint256 internal constant TIMESTAMP_INDEX = 9; //in execution payload uint256 internal constant WITHDRAWALS_INDEX = 14; // in withdrawal uint256 internal constant WITHDRAWAL_VALIDATOR_INDEX_INDEX = 1; uint256 internal constant WITHDRAWAL_VALIDATOR_AMOUNT_INDEX = 3; //Misc Constants /// @notice The number of slots each epoch in the beacon chain uint64 internal constant SLOTS_PER_EPOCH = 32; /// @notice The number of seconds in a slot in the beacon chain uint64 internal constant SECONDS_PER_SLOT = 12; /// @notice Number of seconds per epoch: 384 == 32 slots/epoch * 12 seconds/slot uint64 internal constant SECONDS_PER_EPOCH = SLOTS_PER_EPOCH * SECONDS_PER_SLOT; bytes8 internal constant UINT64_MASK = 0xffffffffffffffff; /// @notice This struct contains the merkle proofs and leaves needed to verify a partial/full withdrawal struct WithdrawalProof { bytes withdrawalProof; bytes slotProof; bytes executionPayloadProof; bytes timestampProof; bytes historicalSummaryBlockRootProof; uint64 blockRootIndex; uint64 historicalSummaryIndex; uint64 withdrawalIndex; bytes32 blockRoot; bytes32 slotRoot; bytes32 timestampRoot; bytes32 executionPayloadRoot; } /// @notice This struct contains the root and proof for verifying the state root against the oracle block root struct StateRootProof { bytes32 beaconStateRoot; bytes proof; } /** * @notice This function verifies merkle proofs of the fields of a certain validator against a beacon chain state root * @param validatorIndex the index of the proven validator * @param beaconStateRoot is the beacon chain state root to be proven against. * @param validatorFieldsProof is the data used in proving the validator's fields * @param validatorFields the claimed fields of the validator */ function verifyValidatorFields( bytes32 beaconStateRoot, bytes32[] calldata validatorFields, bytes calldata validatorFieldsProof, uint40 validatorIndex ) internal view { require( validatorFields.length == 2 ** VALIDATOR_FIELD_TREE_HEIGHT, "BeaconChainProofs.verifyValidatorFields: Validator fields has incorrect length" ); /** * Note: the length of the validator merkle proof is BeaconChainProofs.VALIDATOR_TREE_HEIGHT + 1. * There is an additional layer added by hashing the root with the length of the validator list */ require( validatorFieldsProof.length == 32 * ((VALIDATOR_TREE_HEIGHT + 1) + BEACON_STATE_FIELD_TREE_HEIGHT), "BeaconChainProofs.verifyValidatorFields: Proof has incorrect length" ); uint256 index = (VALIDATOR_TREE_ROOT_INDEX << (VALIDATOR_TREE_HEIGHT + 1)) | uint256(validatorIndex); // merkleize the validatorFields to get the leaf to prove bytes32 validatorRoot = Merkle.merkleizeSha256(validatorFields); // verify the proof of the validatorRoot against the beaconStateRoot require( Merkle.verifyInclusionSha256({ proof: validatorFieldsProof, root: beaconStateRoot, leaf: validatorRoot, index: index }), "BeaconChainProofs.verifyValidatorFields: Invalid merkle proof" ); } /** * @notice This function verifies the latestBlockHeader against the state root. the latestBlockHeader is * a tracked in the beacon state. * @param beaconStateRoot is the beacon chain state root to be proven against. * @param stateRootProof is the provided merkle proof * @param latestBlockRoot is hashtree root of the latest block header in the beacon state */ function verifyStateRootAgainstLatestBlockRoot( bytes32 latestBlockRoot, bytes32 beaconStateRoot, bytes calldata stateRootProof ) internal view { require( stateRootProof.length == 32 * (BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT), "BeaconChainProofs.verifyStateRootAgainstLatestBlockRoot: Proof has incorrect length" ); //Next we verify the slot against the blockRoot require( Merkle.verifyInclusionSha256({ proof: stateRootProof, root: latestBlockRoot, leaf: beaconStateRoot, index: STATE_ROOT_INDEX }), "BeaconChainProofs.verifyStateRootAgainstLatestBlockRoot: Invalid latest block header root merkle proof" ); } /** * @notice This function verifies the slot and the withdrawal fields for a given withdrawal * @param withdrawalProof is the provided set of merkle proofs * @param withdrawalFields is the serialized withdrawal container to be proven */ function verifyWithdrawal( bytes32 beaconStateRoot, bytes32[] calldata withdrawalFields, WithdrawalProof calldata withdrawalProof, uint64 denebForkTimestamp ) internal view { require( withdrawalFields.length == 2 ** WITHDRAWAL_FIELD_TREE_HEIGHT, "BeaconChainProofs.verifyWithdrawal: withdrawalFields has incorrect length" ); require( withdrawalProof.blockRootIndex < 2 ** BLOCK_ROOTS_TREE_HEIGHT, "BeaconChainProofs.verifyWithdrawal: blockRootIndex is too large" ); require( withdrawalProof.withdrawalIndex < 2 ** WITHDRAWALS_TREE_HEIGHT, "BeaconChainProofs.verifyWithdrawal: withdrawalIndex is too large" ); require( withdrawalProof.historicalSummaryIndex < 2 ** HISTORICAL_SUMMARIES_TREE_HEIGHT, "BeaconChainProofs.verifyWithdrawal: historicalSummaryIndex is too large" ); //Note: post deneb hard fork, the number of exection payload header fields increased from 15->17, adding an extra level to the tree height uint256 executionPayloadHeaderFieldTreeHeight = (getWithdrawalTimestamp(withdrawalProof) < denebForkTimestamp) ? EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_CAPELLA : EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_DENEB; require( withdrawalProof.withdrawalProof.length == 32 * (executionPayloadHeaderFieldTreeHeight + WITHDRAWALS_TREE_HEIGHT + 1), "BeaconChainProofs.verifyWithdrawal: withdrawalProof has incorrect length" ); require( withdrawalProof.executionPayloadProof.length == 32 * (BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT + BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT), "BeaconChainProofs.verifyWithdrawal: executionPayloadProof has incorrect length" ); require( withdrawalProof.slotProof.length == 32 * (BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT), "BeaconChainProofs.verifyWithdrawal: slotProof has incorrect length" ); require( withdrawalProof.timestampProof.length == 32 * (executionPayloadHeaderFieldTreeHeight), "BeaconChainProofs.verifyWithdrawal: timestampProof has incorrect length" ); require( withdrawalProof.historicalSummaryBlockRootProof.length == 32 * (BEACON_STATE_FIELD_TREE_HEIGHT + (HISTORICAL_SUMMARIES_TREE_HEIGHT + 1) + 1 + (BLOCK_ROOTS_TREE_HEIGHT)), "BeaconChainProofs.verifyWithdrawal: historicalSummaryBlockRootProof has incorrect length" ); /** * Note: Here, the "1" in "1 + (BLOCK_ROOTS_TREE_HEIGHT)" signifies that extra step of choosing the "block_root_summary" within the individual * "historical_summary". Everywhere else it signifies merkelize_with_mixin, where the length of an array is hashed with the root of the array, * but not here. */ uint256 historicalBlockHeaderIndex = (HISTORICAL_SUMMARIES_INDEX << ((HISTORICAL_SUMMARIES_TREE_HEIGHT + 1) + 1 + (BLOCK_ROOTS_TREE_HEIGHT))) | (uint256(withdrawalProof.historicalSummaryIndex) << (1 + (BLOCK_ROOTS_TREE_HEIGHT))) | (BLOCK_SUMMARY_ROOT_INDEX << (BLOCK_ROOTS_TREE_HEIGHT)) | uint256(withdrawalProof.blockRootIndex); require( Merkle.verifyInclusionSha256({ proof: withdrawalProof.historicalSummaryBlockRootProof, root: beaconStateRoot, leaf: withdrawalProof.blockRoot, index: historicalBlockHeaderIndex }), "BeaconChainProofs.verifyWithdrawal: Invalid historicalsummary merkle proof" ); //Next we verify the slot against the blockRoot require( Merkle.verifyInclusionSha256({ proof: withdrawalProof.slotProof, root: withdrawalProof.blockRoot, leaf: withdrawalProof.slotRoot, index: SLOT_INDEX }), "BeaconChainProofs.verifyWithdrawal: Invalid slot merkle proof" ); { // Next we verify the executionPayloadRoot against the blockRoot uint256 executionPayloadIndex = (BODY_ROOT_INDEX << (BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT)) | EXECUTION_PAYLOAD_INDEX; require( Merkle.verifyInclusionSha256({ proof: withdrawalProof.executionPayloadProof, root: withdrawalProof.blockRoot, leaf: withdrawalProof.executionPayloadRoot, index: executionPayloadIndex }), "BeaconChainProofs.verifyWithdrawal: Invalid executionPayload merkle proof" ); } // Next we verify the timestampRoot against the executionPayload root require( Merkle.verifyInclusionSha256({ proof: withdrawalProof.timestampProof, root: withdrawalProof.executionPayloadRoot, leaf: withdrawalProof.timestampRoot, index: TIMESTAMP_INDEX }), "BeaconChainProofs.verifyWithdrawal: Invalid timestamp merkle proof" ); { /** * Next we verify the withdrawal fields against the executionPayloadRoot: * First we compute the withdrawal_index, then we merkleize the * withdrawalFields container to calculate the withdrawalRoot. * * Note: Merkleization of the withdrawals root tree uses MerkleizeWithMixin, i.e., the length of the array is hashed with the root of * the array. Thus we shift the WITHDRAWALS_INDEX over by WITHDRAWALS_TREE_HEIGHT + 1 and not just WITHDRAWALS_TREE_HEIGHT. */ uint256 withdrawalIndex = (WITHDRAWALS_INDEX << (WITHDRAWALS_TREE_HEIGHT + 1)) | uint256(withdrawalProof.withdrawalIndex); bytes32 withdrawalRoot = Merkle.merkleizeSha256(withdrawalFields); require( Merkle.verifyInclusionSha256({ proof: withdrawalProof.withdrawalProof, root: withdrawalProof.executionPayloadRoot, leaf: withdrawalRoot, index: withdrawalIndex }), "BeaconChainProofs.verifyWithdrawal: Invalid withdrawal merkle proof" ); } } /** * @notice This function replicates the ssz hashing of a validator's pubkey, outlined below: * hh := ssz.NewHasher() * hh.PutBytes(validatorPubkey[:]) * validatorPubkeyHash := hh.Hash() * hh.Reset() */ function hashValidatorBLSPubkey( bytes memory validatorPubkey ) internal pure returns (bytes32 pubkeyHash) { require(validatorPubkey.length == 48, "Input should be 48 bytes in length"); return sha256(abi.encodePacked(validatorPubkey, bytes16(0))); } /** * @dev Retrieve the withdrawal timestamp */ function getWithdrawalTimestamp( WithdrawalProof memory withdrawalProof ) internal pure returns (uint64) { return Endian.fromLittleEndianUint64(withdrawalProof.timestampRoot); } /** * @dev Converts the withdrawal's slot to an epoch */ function getWithdrawalEpoch( WithdrawalProof memory withdrawalProof ) internal pure returns (uint64) { return Endian.fromLittleEndianUint64(withdrawalProof.slotRoot) / SLOTS_PER_EPOCH; } /** * Indices for validator fields (refer to consensus specs): * 0: pubkey * 1: withdrawal credentials * 2: effective balance * 3: slashed? * 4: activation elligibility epoch * 5: activation epoch * 6: exit epoch * 7: withdrawable epoch */ /** * @dev Retrieves a validator's pubkey hash */ function getPubkeyHash(bytes32[] memory validatorFields) internal pure returns (bytes32) { return validatorFields[VALIDATOR_PUBKEY_INDEX]; } function getWithdrawalCredentials( bytes32[] memory validatorFields ) internal pure returns (bytes32) { return validatorFields[VALIDATOR_WITHDRAWAL_CREDENTIALS_INDEX]; } /** * @dev Retrieves a validator's effective balance (in gwei) */ function getEffectiveBalanceGwei( bytes32[] memory validatorFields ) internal pure returns (uint64) { return Endian.fromLittleEndianUint64(validatorFields[VALIDATOR_BALANCE_INDEX]); } /** * @dev Retrieves a validator's withdrawable epoch */ function getWithdrawableEpoch(bytes32[] memory validatorFields) internal pure returns (uint64) { return Endian.fromLittleEndianUint64(validatorFields[VALIDATOR_WITHDRAWABLE_EPOCH_INDEX]); } /** * Indices for withdrawal fields (refer to consensus specs): * 0: withdrawal index * 1: validator index * 2: execution address * 3: withdrawal amount */ /** * @dev Retrieves a withdrawal's validator index */ function getValidatorIndex(bytes32[] memory withdrawalFields) internal pure returns (uint40) { return uint40( Endian.fromLittleEndianUint64(withdrawalFields[WITHDRAWAL_VALIDATOR_INDEX_INDEX]) ); } /** * @dev Retrieves a withdrawal's withdrawal amount (in gwei) */ function getWithdrawalAmountGwei( bytes32[] memory withdrawalFields ) internal pure returns (uint64) { return Endian.fromLittleEndianUint64(withdrawalFields[WITHDRAWAL_VALIDATOR_AMOUNT_INDEX]); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; library Endian { /** * @notice Converts a little endian-formatted uint64 to a big endian-formatted uint64 * @param lenum little endian-formatted uint64 input, provided as 'bytes32' type * @return n The big endian-formatted uint64 * @dev Note that the input is formatted as a 'bytes32' type (i.e. 256 bits), but it is immediately truncated to a uint64 (i.e. 64 bits) * through a right-shift/shr operation. */ function fromLittleEndianUint64(bytes32 lenum) internal pure returns (uint64 n) { // the number needs to be stored in little-endian encoding (ie in bytes 0-8) n = uint64(uint256(lenum >> 192)); return (n >> 56) | ((0x00FF000000000000 & n) >> 40) | ((0x0000FF0000000000 & n) >> 24) | ((0x000000FF00000000 & n) >> 8) | ((0x00000000FF000000 & n) << 8) | ((0x0000000000FF0000 & n) << 24) | ((0x000000000000FF00 & n) << 40) | ((0x00000000000000FF & n) << 56); } }
// SPDX-License-Identifier: MIT // Adapted from OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.0; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The tree and the proofs can be generated using our * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. * You will find a quickstart guide in the readme. * * WARNING: You should avoid using leaf values that are 64 bytes long prior to * hashing, or use a hash function other than keccak256 for hashing leaves. * This is because the concatenation of a sorted pair of internal nodes in * the merkle tree could be reinterpreted as a leaf value. * OpenZeppelin's JavaScript library generates merkle trees that are safe * against this attack out of the box. */ library Merkle { /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. The tree is built assuming `leaf` is * the 0 indexed `index`'th leaf from the bottom left of the tree. * * Note this is for a Merkle tree using the keccak/sha3 hash function */ function verifyInclusionKeccak( bytes memory proof, bytes32 root, bytes32 leaf, uint256 index ) internal pure returns (bool) { return processInclusionProofKeccak(proof, leaf, index) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. The tree is built assuming `leaf` is * the 0 indexed `index`'th leaf from the bottom left of the tree. * * _Available since v4.4._ * * Note this is for a Merkle tree using the keccak/sha3 hash function */ function processInclusionProofKeccak( bytes memory proof, bytes32 leaf, uint256 index ) internal pure returns (bytes32) { require( proof.length != 0 && proof.length % 32 == 0, "Merkle.processInclusionProofKeccak: proof length should be a non-zero multiple of 32" ); bytes32 computedHash = leaf; for (uint256 i = 32; i <= proof.length; i += 32) { if (index % 2 == 0) { // if ith bit of index is 0, then computedHash is a left sibling assembly { mstore(0x00, computedHash) mstore(0x20, mload(add(proof, i))) computedHash := keccak256(0x00, 0x40) index := div(index, 2) } } else { // if ith bit of index is 1, then computedHash is a right sibling assembly { mstore(0x00, mload(add(proof, i))) mstore(0x20, computedHash) computedHash := keccak256(0x00, 0x40) index := div(index, 2) } } } return computedHash; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. The tree is built assuming `leaf` is * the 0 indexed `index`'th leaf from the bottom left of the tree. * * Note this is for a Merkle tree using the sha256 hash function */ function verifyInclusionSha256( bytes memory proof, bytes32 root, bytes32 leaf, uint256 index ) internal view returns (bool) { return processInclusionProofSha256(proof, leaf, index) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. The tree is built assuming `leaf` is * the 0 indexed `index`'th leaf from the bottom left of the tree. * * _Available since v4.4._ * * Note this is for a Merkle tree using the sha256 hash function */ function processInclusionProofSha256( bytes memory proof, bytes32 leaf, uint256 index ) internal view returns (bytes32) { require( proof.length != 0 && proof.length % 32 == 0, "Merkle.processInclusionProofSha256: proof length should be a non-zero multiple of 32" ); bytes32[1] memory computedHash = [leaf]; for (uint256 i = 32; i <= proof.length; i += 32) { if (index % 2 == 0) { // if ith bit of index is 0, then computedHash is a left sibling assembly { mstore(0x00, mload(computedHash)) mstore(0x20, mload(add(proof, i))) if iszero(staticcall(sub(gas(), 2000), 2, 0x00, 0x40, computedHash, 0x20)) { revert(0, 0) } index := div(index, 2) } } else { // if ith bit of index is 1, then computedHash is a right sibling assembly { mstore(0x00, mload(add(proof, i))) mstore(0x20, mload(computedHash)) if iszero(staticcall(sub(gas(), 2000), 2, 0x00, 0x40, computedHash, 0x20)) { revert(0, 0) } index := div(index, 2) } } } return computedHash[0]; } /** @notice this function returns the merkle root of a tree created from a set of leaves using sha256 as its hash function @param leaves the leaves of the merkle tree @return The computed Merkle root of the tree. @dev A pre-condition to this function is that leaves.length is a power of two. If not, the function will merkleize the inputs incorrectly. */ function merkleizeSha256(bytes32[] memory leaves) internal pure returns (bytes32) { //there are half as many nodes in the layer above the leaves uint256 numNodesInLayer = leaves.length / 2; //create a layer to store the internal nodes bytes32[] memory layer = new bytes32[](numNodesInLayer); //fill the layer with the pairwise hashes of the leaves for (uint256 i = 0; i < numNodesInLayer; i++) { layer[i] = sha256(abi.encodePacked(leaves[2 * i], leaves[2 * i + 1])); } //the next layer above has half as many nodes numNodesInLayer /= 2; //while we haven't computed the root while (numNodesInLayer != 0) { //overwrite the first numNodesInLayer nodes in layer with the pairwise hashes of their children for (uint256 i = 0; i < numNodesInLayer; i++) { layer[i] = sha256(abi.encodePacked(layer[2 * i], layer[2 * i + 1])); } //the next layer above has half as many nodes numNodesInLayer /= 2; } //the first node in the layer is the root return layer[0]; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; /// @dev Error for 0x0 address inputs error InvalidZeroInput(); /// @dev Error for already added items to a list error AlreadyAdded(); /// @dev Error for not found items in a list error NotFound(); /// @dev Error for hitting max TVL error MaxTVLReached(); /// @dev Error for caller not having permissions error NotRestakeManagerAdmin(); /// @dev Error for call not coming from deposit queue contract error NotDepositQueue(); /// @dev Error for contract being paused error ContractPaused(); /// @dev Error for exceeding max basis points (100%) error OverMaxBasisPoints(); /// @dev Error for invalid token decimals for collateral tokens (must be 18) error InvalidTokenDecimals(uint8 expected, uint8 actual); /// @dev Error when withdraw is already completed error WithdrawAlreadyCompleted(); /// @dev Error when a different address tries to complete withdraw error NotOriginalWithdrawCaller(address expectedCaller); /// @dev Error when caller does not have OD admin role error NotOperatorDelegatorAdmin(); /// @dev Error when caller does not have Oracle Admin role error NotOracleAdmin(); /// @dev Error when caller is not RestakeManager contract error NotRestakeManager(); /// @dev Errror when caller does not have ETH Restake Admin role error NotNativeEthRestakeAdmin(); /// @dev Error when delegation address was already set - cannot be set again error DelegateAddressAlreadySet(); /// @dev Error when caller does not have ERC20 Rewards Admin role error NotERC20RewardsAdmin(); /// @dev Error when sending ETH fails error TransferFailed(); /// @dev Error when caller does not have ETH Minter Burner Admin role error NotEzETHMinterBurner(); /// @dev Error when caller does not have Token Admin role error NotTokenAdmin(); /// @dev Error when price oracle is not configured error OracleNotFound(); /// @dev Error when price oracle data is stale error OraclePriceExpired(); /// @dev Error when array lengths do not match error MismatchedArrayLengths(); /// @dev Error when caller does not have Deposit Withdraw Pauser role error NotDepositWithdrawPauser(); /// @dev Error when an individual token TVL is over the max error MaxTokenTVLReached(); /// @dev Error when Oracle price is invalid error InvalidOraclePrice(); /// @dev Error when calling an invalid function error NotImplemented(); /// @dev Error when calculating token amounts is invalid error InvalidTokenAmount(); /// @dev Error when timestamp is invalid - likely in the past error InvalidTimestamp(uint256 timestamp); /// @dev Error when trade does not meet minimum output amount error InsufficientOutputAmount(); /// @dev Error when the token received over the bridge is not the one expected error InvalidTokenReceived(); /// @dev Error when the origin address is not whitelisted error InvalidOrigin(); /// @dev Error when the sender is not expected error InvalidSender(address expectedSender, address actualSender); /// @dev error when function returns 0 amount error InvalidZeroOutput(); /// @dev error when xRenzoBridge does not have enough balance to pay for fee error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees); /// @dev error when source chain is not expected error InvalidSourceChain(uint64 expectedCCIPChainSelector, uint64 actualCCIPChainSelector); /// @dev Error when an unauthorized address tries to call the bridge function on the L2 error UnauthorizedBridgeSweeper(); /// @dev Error when caller does not have BRIDGE_ADMIN role error NotBridgeAdmin(); /// @dev Error when caller does not have PRICE_FEED_SENDER role error NotPriceFeedSender(); /// @dev Error for connext price Feed unauthorised call error UnAuthorisedCall(); /// @dev Error for no price feed configured on L2 error PriceFeedNotAvailable(); /// @dev Error for invalid bridge fee share configuration error InvalidBridgeFeeShare(uint256 bridgeFee); /// @dev Error for invalid sweep batch size error InvalidSweepBatchSize(uint256 batchSize); /// @dev Error when caller does not have Withdraw Queue admin role error NotWithdrawQueueAdmin(); /// @dev Error when caller try to withdraw more than Buffer error NotEnoughWithdrawBuffer(); /// @dev Error when caller try to claim withdraw before cooldown period error EarlyClaim(); /// @dev Error when caller try to withdraw for unsupported asset error UnsupportedWithdrawAsset(); /// @dev Error when caller try to claim invalidWithdrawIndex error InvalidWithdrawIndex(); /// @dev Error when TVL was expected to be 0 error InvalidTVL(); /// @dev Error when incorrect BeaconChainStrategy is set for LST in completeQueuedWithdrawal error IncorrectStrategy(); /// @dev Error when adding new OperatorDelegator which is not delegated error OperatoDelegatorNotDelegated(); /// @dev Error when emergency tracking already tracked withdrawal error WithdrawalAlreadyTracked(); /// @dev Error when emergency tracking already completed withdrawal error WithdrawalAlreadyCompleted(); /// @dev Error when caller does not have Emergency Withdraw Tracking Admin role error NotEmergencyWithdrawTrackingAdmin(); /// @dev Error when strategy does not have specified underlying error InvalidStrategy(); /// @dev Error when strategy already set and hold non zero token balance error NonZeroUnderlyingStrategyExist(); /// @dev Error when caller tried to claim queued withdrawal when not filled error QueuedWithdrawalNotFilled();
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import "./Delegation/IOperatorDelegator.sol"; import "./Deposits/IDepositQueue.sol"; interface IRestakeManager { function stakeEthInOperatorDelegator( IOperatorDelegator operatorDelegator, bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot ) external payable; function depositTokenRewardsFromProtocol(IERC20 _token, uint256 _amount) external; function depositQueue() external view returns (IDepositQueue); function calculateTVLs() external view returns (uint256[][] memory, uint256[] memory, uint256); function depositETH() external payable; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; interface IRoleManager { /// @dev Determines if the specified address has permissions to manage RoleManager /// @param potentialAddress Address to check function isRoleManagerAdmin(address potentialAddress) external view returns (bool); /// @dev Determines if the specified address has permission to mint or burn ezETH tokens /// @param potentialAddress Address to check function isEzETHMinterBurner(address potentialAddress) external view returns (bool); /// @dev Determines if the specified address has permission to update config on the OperatorDelgator Contracts /// @param potentialAddress Address to check function isOperatorDelegatorAdmin(address potentialAddress) external view returns (bool); /// @dev Determines if the specified address has permission to update config on the Oracle Contract config /// @param potentialAddress Address to check function isOracleAdmin(address potentialAddress) external view returns (bool); /// @dev Determines if the specified address has permission to update config on the Restake Manager /// @param potentialAddress Address to check function isRestakeManagerAdmin(address potentialAddress) external view returns (bool); /// @dev Determines if the specified address has permission to update config on the Token Contract /// @param potentialAddress Address to check function isTokenAdmin(address potentialAddress) external view returns (bool); /// @dev Determines if the specified address has permission to trigger restaking of native ETH /// @param potentialAddress Address to check function isNativeEthRestakeAdmin(address potentialAddress) external view returns (bool); /// @dev Determines if the specified address has permission to sweep and deposit ERC20 Rewards /// @param potentialAddress Address to check function isERC20RewardsAdmin(address potentialAddress) external view returns (bool); /// @dev Determines if the specified address has permission to pause deposits and withdraws /// @param potentialAddress Address to check function isDepositWithdrawPauser(address potentialAddress) external view returns (bool); /// @dev Determines if the specified address has permission to set whitelisted origin in xRenzoBridge /// @param potentialAddress Address to check function isBridgeAdmin(address potentialAddress) external view returns (bool); /// @dev Determined if the specified address has permission to send price feed of ezETH to L2 /// @param potentialAddress Address to check function isPriceFeedSender(address potentialAddress) external view returns (bool); /// @dev Determine if the specified address haas permission to update Withdraw Queue params /// @param potentialAddress Address to check function isWithdrawQueueAdmin(address potentialAddress) external view returns (bool); /// @dev Determine if the specified address has permission to track emergency pending queued withdrawals /// @param potentialAddress Address to check function isEmergencyWithdrawTrackingAdmin( address potentialAddress ) external view returns (bool); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; interface IWithdrawQueue { /// @dev To get available value to withdraw from buffer /// @param _asset address of token function getAvailableToWithdraw(address _asset) external view returns (uint256); /// @dev To get the withdraw buffer target of given asset /// @param _asset address of token function withdrawalBufferTarget(address _asset) external view returns (uint256); /// @dev To get the current Target Buffer Deficit /// @param _asset address of token function getWithdrawDeficit(address _asset) external view returns (uint256); /// @dev Fill ERC20 Withdraw Buffer /// @param _asset the token address to fill the respective buffer /// @param _amount amount of token to fill with function fillERC20WithdrawBuffer(address _asset, uint256 _amount) external; /// @dev to get the withdrawRequests for particular user /// @param _user address of the user function withdrawRequests(address _user) external view returns (uint256[] memory); /// @dev Fill ETH Withdraw buffer function fillEthWithdrawBuffer() external payable; }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DelegateAddressAlreadySet","type":"error"},{"inputs":[],"name":"IncorrectStrategy","type":"error"},{"inputs":[],"name":"InvalidStrategy","type":"error"},{"inputs":[],"name":"InvalidZeroInput","type":"error"},{"inputs":[],"name":"MismatchedArrayLengths","type":"error"},{"inputs":[],"name":"NonZeroUnderlyingStrategyExist","type":"error"},{"inputs":[],"name":"NotEmergencyWithdrawTrackingAdmin","type":"error"},{"inputs":[],"name":"NotFound","type":"error"},{"inputs":[],"name":"NotNativeEthRestakeAdmin","type":"error"},{"inputs":[],"name":"NotOperatorDelegatorAdmin","type":"error"},{"inputs":[],"name":"NotRestakeManager","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"WithdrawalAlreadyCompleted","type":"error"},{"inputs":[],"name":"WithdrawalAlreadyTracked","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldBaseGasAmountSpent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBaseGasAmountSpent","type":"uint256"}],"name":"BaseGasAmountSpentUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"delegateAddress","type":"address"}],"name":"DelegationAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"gasRefunded","type":"uint256"}],"name":"GasRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"gasSpent","type":"uint256"}],"name":"GasSpent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"rewardDestination","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsForwarded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"contract IStrategy","name":"strategy","type":"address"}],"name":"TokenStrategyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalRoot","type":"bytes32"},{"indexed":false,"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"shares","type":"uint256[]"}],"name":"WithdrawCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawRoot","type":"bytes32"},{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"address","name":"delegatedTo","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawer","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startBlock","type":"uint256"},{"indexed":false,"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"shares","type":"uint256[]"}],"name":"WithdrawStarted","type":"event"},{"inputs":[],"name":"IS_NATIVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STAKE_BUT_NOT_VERIFIED_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activateRestaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"adminGasSpentInWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseGasAmountSpent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"delegatedTo","type":"address"},{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint32","name":"startBlock","type":"uint32"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"shares","type":"uint256[]"}],"internalType":"struct IDelegationManager.Withdrawal","name":"withdrawal","type":"tuple"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"middlewareTimesIndex","type":"uint256"}],"name":"completeQueuedWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delegateAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegationManager","outputs":[{"internalType":"contract IDelegationManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eigenPod","outputs":[{"internalType":"contract IEigenPod","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eigenPodManager","outputs":[{"internalType":"contract IEigenPodManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"delegatedTo","type":"address"},{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint32","name":"startBlock","type":"uint32"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"shares","type":"uint256[]"}],"internalType":"struct IDelegationManager.Withdrawal[]","name":"withdrawals","type":"tuple[]"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"name":"emergencyTrackQueuedWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getStakedETHBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IStrategy","name":"_strategy","type":"address"}],"name":"getStrategyIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"getTokenBalanceFromStrategy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IRoleManager","name":"_roleManager","type":"address"},{"internalType":"contract IStrategyManager","name":"_strategyManager","type":"address"},{"internalType":"contract IRestakeManager","name":"_restakeManager","type":"address"},{"internalType":"contract IDelegationManager","name":"_delegationManager","type":"address"},{"internalType":"contract IEigenPodManager","name":"_eigenPodManager","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pendingUnstakedDelayedWithdrawalAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"tokenAmounts","type":"uint256[]"}],"name":"queueWithdrawals","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"queuedShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"queuedWithdrawal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokenList","type":"address[]"},{"internalType":"uint256[]","name":"amountsToWithdraw","type":"uint256[]"},{"internalType":"address","name":"recipient","type":"address"}],"name":"recoverTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"restakeManager","outputs":[{"internalType":"contract IRestakeManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"roleManager","outputs":[{"internalType":"contract IRoleManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_baseGasAmountSpent","type":"uint256"}],"name":"setBaseGasAmountSpent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegateAddress","type":"address"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"internalType":"struct ISignatureUtils.SignatureWithExpiry","name":"approverSignatureAndExpiry","type":"tuple"},{"internalType":"bytes32","name":"approverSalt","type":"bytes32"}],"name":"setDelegateAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"contract IStrategy","name":"_strategy","type":"address"}],"name":"setTokenStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes32","name":"depositDataRoot","type":"bytes32"}],"name":"stakeEth","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"stakedButNotVerifiedEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startDelayedWithdrawUnstakedETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strategyManager","outputs":[{"internalType":"contract IStrategyManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"name":"tokenStrategyMapping","outputs":[{"internalType":"contract IStrategy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"validatorStakedButNotVerifiedEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"oracleTimestamp","type":"uint64"},{"components":[{"internalType":"bytes32","name":"beaconStateRoot","type":"bytes32"},{"internalType":"bytes","name":"proof","type":"bytes"}],"internalType":"struct BeaconChainProofs.StateRootProof","name":"stateRootProof","type":"tuple"},{"components":[{"internalType":"bytes","name":"withdrawalProof","type":"bytes"},{"internalType":"bytes","name":"slotProof","type":"bytes"},{"internalType":"bytes","name":"executionPayloadProof","type":"bytes"},{"internalType":"bytes","name":"timestampProof","type":"bytes"},{"internalType":"bytes","name":"historicalSummaryBlockRootProof","type":"bytes"},{"internalType":"uint64","name":"blockRootIndex","type":"uint64"},{"internalType":"uint64","name":"historicalSummaryIndex","type":"uint64"},{"internalType":"uint64","name":"withdrawalIndex","type":"uint64"},{"internalType":"bytes32","name":"blockRoot","type":"bytes32"},{"internalType":"bytes32","name":"slotRoot","type":"bytes32"},{"internalType":"bytes32","name":"timestampRoot","type":"bytes32"},{"internalType":"bytes32","name":"executionPayloadRoot","type":"bytes32"}],"internalType":"struct BeaconChainProofs.WithdrawalProof[]","name":"withdrawalProofs","type":"tuple[]"},{"internalType":"bytes[]","name":"validatorFieldsProofs","type":"bytes[]"},{"internalType":"bytes32[][]","name":"validatorFields","type":"bytes32[][]"},{"internalType":"bytes32[][]","name":"withdrawalFields","type":"bytes32[][]"}],"name":"verifyAndProcessWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"oracleTimestamp","type":"uint64"},{"components":[{"internalType":"bytes32","name":"beaconStateRoot","type":"bytes32"},{"internalType":"bytes","name":"proof","type":"bytes"}],"internalType":"struct BeaconChainProofs.StateRootProof","name":"stateRootProof","type":"tuple"},{"internalType":"uint40[]","name":"validatorIndices","type":"uint40[]"},{"internalType":"bytes[]","name":"withdrawalCredentialProofs","type":"bytes[]"},{"internalType":"bytes32[][]","name":"validatorFields","type":"bytes32[][]"}],"name":"verifyWithdrawalCredentials","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountToWithdraw","type":"uint256"}],"name":"withdrawNonBeaconChainETHBalanceWei","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b614e1c80620000f36000396000f3fe6080604052600436106102065760003560e01c80636d96a2aa11610118578063d1464931116100a0578063e2c834451161006f578063e2c8344514610849578063ea4d3c9b14610869578063ec54aa7b14610889578063ec730177146108a9578063ff0996b5146108c957600080fd5b8063d1464931146107c6578063dc560c88146107dc578063dda3346c14610809578063e251ef521461082957600080fd5b8063ae2814d2116100e7578063ae2814d21461070e578063b3d4262114610723578063b915588514610763578063bc79a36514610790578063c26f2056146107a657600080fd5b80636d96a2aa1461069b5780639ebf4ab1146106bb578063a0d58d8a146106ce578063a3aae136146106ee57600080fd5b8063397bfbac1161019b578063479d39761161016a578063479d3976146105fe57806347e7ef24146106265780635299ac17146106465780635361477b14610666578063573803fb1461068657600080fd5b8063397bfbac1461058857806339b70e381461059e5780633f65cf19146105be5780634665bcda146105de57600080fd5b8063127842a4116101d7578063127842a4146104f55780631459457a1461052b57806323e481751461054b5780632e992fc51461056b57600080fd5b8062435da514610448578062cb637e146104855780630cca214f146104a55780630cd4649e146104e057600080fd5b3661044357603a546001600160a01b031633036102e457603560009054906101000a90046001600160a01b03166001600160a01b031663f617eecc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610270573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102949190613a63565b6001600160a01b0316636c0d86bd346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156102ce57600080fd5b505af11580156102e2573d6000803e3d6000fd5b005b326000908152603e602052604081205447901561031b576103036108e9565b915061030f8282613a96565b90508060000361031b57005b60355460408051633d85fbb360e21b815290516000926001600160a01b03169163f617eecc9160048083019260209291908290030181865afa158015610365573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103899190613a63565b90506000816001600160a01b03168360405160006040518083038185875af1925050503d80600081146103d8576040519150601f19603f3d011682016040523d82523d6000602084013e6103dd565b606091505b50509050806103ff576040516312171d8360e31b815260040160405180910390fd5b604080516001600160a01b0384168152602081018590527f64459fab7324199920bec86f9ce814dab17621d386f548c8a7c4e638d28fb8f4910160405180910390a1005b600080fd5b34801561045457600080fd5b50603354610468906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561049157600080fd5b506102e26104a0366004613af4565b6109bd565b3480156104b157600080fd5b506104d26104c0366004613b6b565b60416020526000908152604090205481565b60405190815260200161047c565b3480156104ec57600080fd5b506102e261125a565b34801561050157600080fd5b50610468610510366004613b84565b6036602052600090815260409020546001600160a01b031681565b34801561053757600080fd5b506102e2610546366004613ba1565b61135e565b34801561055757600080fd5b506104d2610566366004613c12565b611612565b34801561057757600080fd5b506104d26801bc16d674ec80000081565b34801561059457600080fd5b506104d2603b5481565b3480156105aa57600080fd5b50603454610468906001600160a01b031681565b3480156105ca57600080fd5b506102e26105d9366004613cb1565b611dfb565b3480156105ea57600080fd5b50603954610468906001600160a01b031681565b34801561060a57600080fd5b5061046873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b34801561063257600080fd5b506104d2610641366004613d7f565b611ff7565b34801561065257600080fd5b506102e2610661366004613dab565b61209f565b34801561067257600080fd5b506102e2610681366004613e5d565b6123a8565b34801561069257600080fd5b506104d261254f565b3480156106a757600080fd5b50603754610468906001600160a01b031681565b6102e26106c9366004613f81565b61268b565b3480156106da57600080fd5b506104d26106e9366004613b84565b61287d565b3480156106fa57600080fd5b50603a54610468906001600160a01b031681565b34801561071a57600080fd5b506102e26129b1565b34801561072f57600080fd5b5061075361073e366004613b6b565b60406020819052600091825290205460ff1681565b604051901515815260200161047c565b34801561076f57600080fd5b506104d261077e366004613b84565b603e6020526000908152604090205481565b34801561079c57600080fd5b506104d2603d5481565b3480156107b257600080fd5b506102e26107c1366004613c12565b612a9e565b3480156107d257600080fd5b506104d2603c5481565b3480156107e857600080fd5b506104d26107f7366004613b84565b603f6020526000908152604090205481565b34801561081557600080fd5b506102e2610824366004614082565b612f09565b34801561083557600080fd5b506102e2610844366004614153565b612ffd565b34801561085557600080fd5b506102e2610864366004613d7f565b613117565b34801561087557600080fd5b50603854610468906001600160a01b031681565b34801561089557600080fd5b506102e26108a4366004613b6b565b613202565b3480156108b557600080fd5b506104d26108c4366004613b84565b613301565b3480156108d557600080fd5b50603554610468906001600160a01b031681565b326000908152603e602052604081205481904710156109085747610919565b326000908152603e60205260409020545b604051909150600090329083156108fc0290849084818181858888f1935050505090508061095a576040516312171d8360e31b815260040160405180910390fd5b326000908152603e602052604081208054849290610979908490613a96565b909155505060408051328152602081018490527f667ad9c7167aea9bfcff8b321015abb0d8b77cf151a377e09e12b9017f9889fd910160405180910390a150919050565b6109c56134b1565b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa158015610a0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a31919061424e565b610a4e5760405163bcefa34f60e01b815260040160405180910390fd5b60005a9050610a6060a0860186614270565b84149050610a8157604051632b477e7160e11b815260040160405180910390fd5b6038546040516360d7faed60e01b81526001600160a01b03909116906360d7faed90610aba90889088908890889060019060040161443d565b600060405180830381600087803b158015610ad457600080fd5b505af1158015610ae8573d6000803e3d6000fd5b505050506000603560009054906101000a90046001600160a01b03166001600160a01b031663f617eecc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b659190613a63565b6001600160a01b03166351a2d6d16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ba2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc69190613a63565b905060005b84811015611179576000868683818110610be757610be76144b0565b9050602002016020810190610bfc9190613b84565b6001600160a01b031603610c235760405163862a606760e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee868683818110610c4a57610c4a6144b0565b9050602002016020810190610c5f9190613b84565b6001600160a01b031614158015610d305750603860009054906101000a90046001600160a01b03166001600160a01b0316639104c3196040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610cc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cea9190613a63565b6001600160a01b0316610d0060a0890189614270565b83818110610d1057610d106144b0565b9050602002016020810190610d259190613b84565b6001600160a01b0316145b15610d4e57604051630b049d2560e11b815260040160405180910390fd5b610d5b60c0880188614270565b82818110610d6b57610d6b6144b0565b90506020020135603f6000888885818110610d8857610d886144b0565b9050602002016020810190610d9d9190613b84565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254610dcc9190613a96565b9091555073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9050868683818110610df957610df96144b0565b9050602002016020810190610e0e9190613b84565b6001600160a01b031614611171576000826001600160a01b0316637be71216888885818110610e3f57610e3f6144b0565b9050602002016020810190610e549190613b84565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610e98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ebc91906144c6565b90506000878784818110610ed257610ed26144b0565b9050602002016020810190610ee79190613b84565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015610f2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5191906144c6565b905081156111365781811115610f675781610f69565b805b9150610f758282613a96565b9050611029603560009054906101000a90046001600160a01b03166001600160a01b031663f617eecc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff19190613a63565b838a8a87818110611004576110046144b0565b90506020020160208101906110199190613b84565b6001600160a01b0316919061350a565b603560009054906101000a90046001600160a01b03166001600160a01b031663f617eecc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561107c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a09190613a63565b6001600160a01b031663d9cd0aaa8989868181106110c0576110c06144b0565b90506020020160208101906110d59190613b84565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101859052604401600060405180830381600087803b15801561111d57600080fd5b505af1158015611131573d6000803e3d6000fd5b505050505b801561116e5761116c888885818110611151576111516144b0565b90506020020160208101906111669190613b84565b826135ea565b505b50505b600101610bcb565b50603854604051632cbd9b6d60e11b81527e31d86140cfa7fee3aca26a490f754ce3afc3c6d2ca211a94172af88ec988e2916001600160a01b03169063597b36da906111c9908a906004016144df565b602060405180830381865afa1580156111e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120a91906144c6565b61121760a0890189614270565b61122460c08b018b614270565b6040516112359594939291906144f2565b60405180910390a16112498261c35061369f565b505061125460018055565b50505050565b6112626134b1565b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa1580156112aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ce919061424e565b6112eb5760405163bcefa34f60e01b815260040160405180910390fd5b603a60009054906101000a90046001600160a01b03166001600160a01b0316630cd4649e6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561133b57600080fd5b505af115801561134f573d6000803e3d6000fd5b5050505061135c60018055565b565b600054610100900460ff161580801561137e5750600054600160ff909116105b806113985750303b158015611398575060005460ff166001145b6114005760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015611423576000805461ff0019166101001790555b6001600160a01b03861661144a5760405163862a606760e01b815260040160405180910390fd5b6001600160a01b0385166114715760405163862a606760e01b815260040160405180910390fd5b6001600160a01b0384166114985760405163862a606760e01b815260040160405180910390fd5b6001600160a01b0383166114bf5760405163862a606760e01b815260040160405180910390fd5b6001600160a01b0382166114e65760405163862a606760e01b815260040160405180910390fd5b6114ee61372f565b603380546001600160a01b038089166001600160a01b0319928316179092556034805488841690831617905560358054878416908316179055603880548684169083161790556039805492851692909116821790556040805163426c083160e11b815290516384d810629160048082019260209290919082900301816000875af1158015611580573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a49190613a63565b603a80546001600160a01b0319166001600160a01b0392909216919091179055801561160a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b600061161c6134b1565b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa158015611664573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611688919061424e565b6116a55760405163bcefa34f60e01b815260040160405180910390fd5b60005a90508483146116ca57604051632b477e7160e11b815260040160405180910390fd5b604080516001808252818301909252600091816020015b604080516060808201835280825260208201526000918101919091528152602001906001900390816116e1579050509050856001600160401b0381111561172a5761172a613def565b604051908082528060200260200182016040528015611753578160200160208202803683370190505b5081600081518110611767576117676144b0565b602090810291909101015152856001600160401b0381111561178b5761178b613def565b6040519080825280602002602001820160405280156117b4578160200160208202803683370190505b50816000815181106117c8576117c86144b0565b602090810291909101810151015260385460405163285e212160e21b81523060048201526000916001600160a01b03169063a178848490602401602060405180830381865afa15801561181f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061184391906144c6565b905060005b87811015611c955773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee898983818110611877576118776144b0565b905060200201602081019061188c9190613b84565b6001600160a01b0316036119bb57603960009054906101000a90046001600160a01b03166001600160a01b0316639104c3196040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119119190613a63565b83600081518110611924576119246144b0565b6020026020010151600001518281518110611941576119416144b0565b60200260200101906001600160a01b031690816001600160a01b031681525050868682818110611973576119736144b0565b905060200201358360008151811061198d5761198d6144b0565b60200260200101516020015182815181106119aa576119aa6144b0565b602002602001018181525050611bbe565b60006036818b8b858181106119d2576119d26144b0565b90506020020160208101906119e79190613b84565b6001600160a01b0390811682526020820192909252604001600020541603611a225760405163862a606760e01b815260040160405180910390fd5b603660008a8a84818110611a3857611a386144b0565b9050602002016020810190611a4d9190613b84565b6001600160a01b03908116825260208201929092526040016000908120548551921691859190611a7f57611a7f6144b0565b6020026020010151600001518281518110611a9c57611a9c6144b0565b60200260200101906001600160a01b031690816001600160a01b031681525050603660008a8a84818110611ad257611ad26144b0565b9050602002016020810190611ae79190613b84565b6001600160a01b0390811682526020820192909252604001600020541663e3dae51c888884818110611b1b57611b1b6144b0565b905060200201356040518263ffffffff1660e01b8152600401611b4091815260200190565b602060405180830381865afa158015611b5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b8191906144c6565b83600081518110611b9457611b946144b0565b6020026020010151602001518281518110611bb157611bb16144b0565b6020026020010181815250505b3083600081518110611bd257611bd26144b0565b6020026020010151604001906001600160a01b031690816001600160a01b03168152505082600081518110611c0957611c096144b0565b6020026020010151602001518181518110611c2657611c266144b0565b6020026020010151603f60008b8b85818110611c4457611c446144b0565b9050602002016020810190611c599190613b84565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254611c889190614560565b9091555050600101611848565b506038546040516306ec6e8160e11b81526000916001600160a01b031690630dd8dd0290611cc79086906004016145dc565b6000604051808303816000875af1158015611ce6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d0e9190810190614676565b600081518110611d2057611d206144b0565b6020908102919091018101516000818152604092839052918220805460ff1916600117905560375485519193507ff7c9db32693636e458573257dad812f58a7c5cc3067e0fad83b601b46947615a92849230926001600160a01b0316918391889143918b9190611d9257611d926144b0565b6020026020010151600001518a600081518110611db157611db16144b0565b602002602001015160200151604051611dd19897969594939291906146fb565b60405180910390a1611de58461c35061369f565b9350505050611df360018055565b949350505050565b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa158015611e43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e67919061424e565b611e845760405163bcefa34f60e01b815260040160405180910390fd5b60005a603a54604051633f65cf1960e01b81529192506001600160a01b031690633f65cf1990611ec6908c908c908c908c908c908c908c908c906004016148c0565b600060405180830381600087803b158015611ee057600080fd5b505af1158015611ef4573d6000803e3d6000fd5b5050505060005b82811015611fdf576000611f63858584818110611f1a57611f1a6144b0565b9050602002810190611f2c9190614270565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061375e92505050565b60008181526041602052604090205490915015611fa757600081815260416020526040812054603b805491929091611f9c908490613a96565b90915550611fc89050565b6801bc16d674ec800000603b6000828254611fc29190613a96565b90915550505b600090815260416020526040812055600101611efb565b50611fec81603d5461369f565b505050505050505050565b60006120016134b1565b6035546001600160a01b0316331461202c576040516342d16b8b60e11b815260040160405180910390fd5b6001600160a01b03838116600090815260366020526040902054161580612051575081155b1561206f5760405163862a606760e01b815260040160405180910390fd5b6120846001600160a01b038416333085613782565b61208e83836135ea565b905061209960018055565b92915050565b6120a76134b1565b603354604051630d5dcbef60e31b81523360048201526001600160a01b0390911690636aee5f7890602401602060405180830381865afa1580156120ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612113919061424e565b6121305760405163cbdd1d2760e01b815260040160405180910390fd5b6001600160a01b0382166121575760405163862a606760e01b815260040160405180910390fd5b6001600160a01b038116158015906122575750816001600160a01b0316816001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d69190613a63565b6001600160a01b0316141580612257575060345460405163198f077960e21b81526001600160a01b0383811660048301529091169063663c1de490602401602060405180830381865afa158015612231573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612255919061424e565b155b1561227557604051632711b74d60e11b815260040160405180910390fd5b6001600160a01b03828116600090815260366020526040902054161580159061231657506001600160a01b03828116600090815260366020526040808220549051630aa794bf60e31b81523060048201529192169063553ca5f890602401602060405180830381865afa1580156122f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061231491906144c6565b115b1561233457604051630f1fd48960e11b815260040160405180910390fd5b6001600160a01b0382811660008181526036602090815260409182902080546001600160a01b031916948616948517905581519283528201929092527f1a654dbe468f1cff27ced5a916efd4120a4155caf290688ab42aebe90554683e910160405180910390a16123a460018055565b5050565b6123b06134b1565b603354604051630d5dcbef60e31b81523360048201526001600160a01b0390911690636aee5f7890602401602060405180830381865afa1580156123f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061241c919061424e565b6124395760405163cbdd1d2760e01b815260040160405180910390fd5b6001600160a01b0383166124605760405163862a606760e01b815260040160405180910390fd5b6037546001600160a01b03161561248a57604051631c52d05d60e11b815260040160405180910390fd5b603780546001600160a01b0319166001600160a01b0385811691821790925560385460405163eea9064b60e01b815292169163eea9064b916124d291869086906004016149a2565b600060405180830381600087803b1580156124ec57600080fd5b505af1158015612500573d6000803e3d6000fd5b50506040516001600160a01b03861681527ffe608947467beb30a90e072fd2fc7d52baecf0935f542011fcd8fa6362a5d5b39250602001905060405180910390a161254a60018055565b505050565b6039546040516360f4062b60e01b815230600482015260009182916001600160a01b03909116906360f4062b90602401602060405180830381865afa15801561259c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c091906144c6565b90506000811261262657603b5473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee600052603f6020527f5d7315d061885134292236184dbffd84acd8b3aaff2ca1613d734d4448806a5a54829161261791614560565b6126219190614560565b612685565b61262f816149e3565b603b5473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee600052603f6020527f5d7315d061885134292236184dbffd84acd8b3aaff2ca1613d734d4448806a5a5461267b9190614560565b6126859190613a96565b91505090565b6035546001600160a01b031633146126b6576040516342d16b8b60e11b815260040160405180910390fd5b603a546040516358eaee7960e01b81526000916001600160a01b0316906358eaee79906126e99089908990600401614a15565b602060405180830381865afa158015612706573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061272a9190614a29565b600281111561273b5761273b6149ff565b0361280a57600061278186868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137ba92505050565b600081815260416020526040812054919250349061279f8284614560565b90506801bc16d674ec8000006127b53485614560565b11156127dd576127ce836801bc16d674ec800000613a96565b91506801bc16d674ec80000090505b6000848152604160205260408120829055603b8054849290612800908490614560565b9091555050505050505b6039546040516326d3918d60e21b81526001600160a01b0390911690639b4e46349034906128449089908990899089908990600401614a4a565b6000604051808303818588803b15801561285d57600080fd5b505af1158015612871573d6000803e3d6000fd5b50505050505050505050565b6034546040516322e2ab0f60e21b815230600482015260009182916001600160a01b0390911690638b8aac3c90602401602060405180830381865afa1580156128ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128ee91906144c6565b905060005b81811015612997576034546040516365e15eb160e11b8152306004820152602481018390526001600160a01b0386811692169063cbc2bd6290604401602060405180830381865afa15801561294c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129709190613a63565b6001600160a01b031603612985579392505050565b8061298f81614a84565b9150506128f3565b5060405163c5723b5160e01b815260040160405180910390fd5b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa1580156129f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a1d919061424e565b612a3a5760405163bcefa34f60e01b815260040160405180910390fd5b603a60009054906101000a90046001600160a01b03166001600160a01b031663baa7145a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612a8a57600080fd5b505af1158015611254573d6000803e3d6000fd5b612aa66134b1565b60335460405163bcc6ce2360e01b81523360048201526001600160a01b039091169063bcc6ce2390602401602060405180830381865afa158015612aee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b12919061424e565b612b2f57604051632efffa9d60e01b815260040160405180910390fd5b808314612b4f57604051632b477e7160e11b815260040160405180910390fd5b60005b83811015612eff576000838383818110612b6e57612b6e6144b0565b9050602002016020810190612b839190613b84565b6001600160a01b031603612baa5760405163862a606760e01b815260040160405180910390fd5b6038546000906001600160a01b031663597b36da878785818110612bd057612bd06144b0565b9050602002810190612be29190614a9d565b6040518263ffffffff1660e01b8152600401612bfe91906144df565b602060405180830381865afa158015612c1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c3f91906144c6565b60008181526040602081905290205490915060ff1615612c725760405163eb3d1dcd60e01b815260040160405180910390fd5b603854604051635bf8375f60e11b8152600481018390526001600160a01b039091169063b7f06ebe90602401602060405180830381865afa158015612cbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cdf919061424e565b612cfc576040516355780d0f60e11b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee848484818110612d2357612d236144b0565b9050602002016020810190612d389190613b84565b6001600160a01b031614158015612e2f5750603860009054906101000a90046001600160a01b03166001600160a01b0316639104c3196040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612d9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc39190613a63565b6001600160a01b0316868684818110612dde57612dde6144b0565b9050602002810190612df09190614a9d565b612dfe9060a0810190614270565b6000818110612e0f57612e0f6144b0565b9050602002016020810190612e249190613b84565b6001600160a01b0316145b15612e4d57604051630b049d2560e11b815260040160405180910390fd5b858583818110612e5f57612e5f6144b0565b9050602002810190612e719190614a9d565b612e7f9060c0810190614270565b6000818110612e9057612e906144b0565b90506020020135603f6000868686818110612ead57612ead6144b0565b9050602002016020810190612ec29190613b84565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254612ef19190614560565b909155505050600101612b52565b5061125460018055565b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa158015612f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f75919061424e565b612f925760405163bcefa34f60e01b815260040160405180910390fd5b603a54604051633768cd1b60e21b81526001600160a01b039091169063dda3346c90612fc690869086908690600401614abd565b600060405180830381600087803b158015612fe057600080fd5b505af1158015612ff4573d6000803e3d6000fd5b50505050505050565b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa158015613045573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613069919061424e565b6130865760405163bcefa34f60e01b815260040160405180910390fd5b60005a603a54604051637128f7a960e11b81529192506001600160a01b03169063e251ef52906130cc908e908e908e908e908e908e908e908e908e908e90600401614b2d565b600060405180830381600087803b1580156130e657600080fd5b505af11580156130fa573d6000803e3d6000fd5b5050505061310a81603d5461369f565b5050505050505050505050565b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa15801561315f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613183919061424e565b6131a05760405163bcefa34f60e01b815260040160405180910390fd5b603a5460405163e2c8344560e01b81526001600160a01b038481166004830152602482018490529091169063e2c8344590604401600060405180830381600087803b1580156131ee57600080fd5b505af115801561160a573d6000803e3d6000fd5b61320a6134b1565b603354604051630d5dcbef60e31b81523360048201526001600160a01b0390911690636aee5f7890602401602060405180830381865afa158015613252573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613276919061424e565b6132935760405163cbdd1d2760e01b815260040160405180910390fd5b806000036132b45760405163862a606760e01b815260040160405180910390fd5b603d5460408051918252602082018390527fbfad24c5385b591e87ef890b13ebedaadf34399714ea0e2dc0f6e4ff69c731dd910160405180910390a1603d8190556132fe60018055565b50565b6001600160a01b0381166000908152603f602052604081205415613436576001600160a01b03808316600090815260366020908152604080832054603f90925291829020549151637a8b263760e01b8152921691637a8b26379161336b9160040190815260200190565b602060405180830381865afa158015613388573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133ac91906144c6565b6001600160a01b0383811660009081526036602052604090819020549051630aa794bf60e31b815230600482015291169063553ca5f890602401602060405180830381865afa158015613403573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061342791906144c6565b6134319190614560565b612099565b6001600160a01b0382811660009081526036602052604090819020549051630aa794bf60e31b815230600482015291169063553ca5f890602401602060405180830381865afa15801561348d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209991906144c6565b6002600154036135035760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016113f7565b6002600155565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa15801561355a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061357e91906144c6565b90506112548463095ea7b360e01b856135978686614560565b6040516001600160a01b03909216602483015260448201526064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261382f565b603454600090613607906001600160a01b0385811691168461350a565b6034546001600160a01b03848116600081815260366020526040908190205490516373d0285560e11b8152908316600482015260248101919091526044810185905291169063e7a050aa906064016020604051808303816000875af1158015613674573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061369891906144c6565b9392505050565b600048825a6136ae9086613a96565b6136b89190614560565b6136c29190614d27565b336000908152603e60205260408120805492935083929091906136e6908490614560565b909155505060408051338152602081018390527f4ff29a094e434f8a698185e97d3a285f4ba26c723f8ec8d2c9914213d61589ca910160405180910390a1505050565b60018055565b600054610100900460ff166137565760405162461bcd60e51b81526004016113f790614d3e565b61135c613904565b600081600081518110613773576137736144b0565b60200260200101519050919050565b6040516001600160a01b03808516602483015283166044820152606481018290526112549085906323b872dd60e01b906084016135b3565b6000600282600060801b6040516020016137d5929190614d89565b60408051601f19818403018152908290526137ef91614dc1565b602060405180830381855afa15801561380c573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061209991906144c6565b6000613884826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661392b9092919063ffffffff16565b90508051600014806138a55750808060200190518101906138a5919061424e565b61254a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016113f7565b600054610100900460ff166137295760405162461bcd60e51b81526004016113f790614d3e565b6060611df3848460008585600080866001600160a01b031685876040516139529190614dc1565b60006040518083038185875af1925050503d806000811461398f576040519150601f19603f3d011682016040523d82523d6000602084013e613994565b606091505b50915091506139a5878383876139b0565b979650505050505050565b60608315613a1f578251600003613a18576001600160a01b0385163b613a185760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016113f7565b5081611df3565b611df38383815115613a345781518083602001fd5b8060405162461bcd60e51b81526004016113f79190614dd3565b6001600160a01b03811681146132fe57600080fd5b600060208284031215613a7557600080fd5b815161369881613a4e565b634e487b7160e01b600052601160045260246000fd5b8181038181111561209957612099613a80565b60008083601f840112613abb57600080fd5b5081356001600160401b03811115613ad257600080fd5b6020830191508360208260051b8501011115613aed57600080fd5b9250929050565b60008060008060608587031215613b0a57600080fd5b84356001600160401b0380821115613b2157600080fd5b9086019060e08289031215613b3557600080fd5b90945060208601359080821115613b4b57600080fd5b50613b5887828801613aa9565b9598909750949560400135949350505050565b600060208284031215613b7d57600080fd5b5035919050565b600060208284031215613b9657600080fd5b813561369881613a4e565b600080600080600060a08688031215613bb957600080fd5b8535613bc481613a4e565b94506020860135613bd481613a4e565b93506040860135613be481613a4e565b92506060860135613bf481613a4e565b91506080860135613c0481613a4e565b809150509295509295909350565b60008060008060408587031215613c2857600080fd5b84356001600160401b0380821115613c3f57600080fd5b613c4b88838901613aa9565b90965094506020870135915080821115613c6457600080fd5b50613c7187828801613aa9565b95989497509550505050565b80356001600160401b0381168114613c9457600080fd5b919050565b600060408284031215613cab57600080fd5b50919050565b60008060008060008060008060a0898b031215613ccd57600080fd5b613cd689613c7d565b975060208901356001600160401b0380821115613cf257600080fd5b613cfe8c838d01613c99565b985060408b0135915080821115613d1457600080fd5b613d208c838d01613aa9565b909850965060608b0135915080821115613d3957600080fd5b613d458c838d01613aa9565b909650945060808b0135915080821115613d5e57600080fd5b50613d6b8b828c01613aa9565b999c989b5096995094979396929594505050565b60008060408385031215613d9257600080fd5b8235613d9d81613a4e565b946020939093013593505050565b60008060408385031215613dbe57600080fd5b8235613dc981613a4e565b91506020830135613dd981613a4e565b809150509250929050565b8035613c9481613a4e565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715613e2757613e27613def565b60405290565b604051601f8201601f191681016001600160401b0381118282101715613e5557613e55613def565b604052919050565b600080600060608486031215613e7257600080fd5b8335613e7d81613a4e565b92506020848101356001600160401b0380821115613e9a57600080fd5b9086019060408289031215613eae57600080fd5b613eb6613e05565b823582811115613ec557600080fd5b8301601f81018a13613ed657600080fd5b803583811115613ee857613ee8613def565b613efa601f8201601f19168701613e2d565b93508084528a86828401011115613f1057600080fd5b80868301878601376000908401860152509081529082013591810191909152929592945050506040919091013590565b60008083601f840112613f5257600080fd5b5081356001600160401b03811115613f6957600080fd5b602083019150836020828501011115613aed57600080fd5b600080600080600060608688031215613f9957600080fd5b85356001600160401b0380821115613fb057600080fd5b613fbc89838a01613f40565b90975095506020880135915080821115613fd557600080fd5b50613fe288828901613f40565b96999598509660400135949350505050565b60006001600160401b0382111561400d5761400d613def565b5060051b60200190565b600082601f83011261402857600080fd5b8135602061403d61403883613ff4565b613e2d565b82815260059290921b8401810191818101908684111561405c57600080fd5b8286015b848110156140775780358352918301918301614060565b509695505050505050565b60008060006060848603121561409757600080fd5b83356001600160401b03808211156140ae57600080fd5b818601915086601f8301126140c257600080fd5b813560206140d261403883613ff4565b82815260059290921b8401810191818101908a8411156140f157600080fd5b948201945b8386101561411857853561410981613a4e565b825294820194908201906140f6565b9750508701359250508082111561412e57600080fd5b5061413b86828701614017565b92505061414a60408501613de4565b90509250925092565b60008060008060008060008060008060c08b8d03121561417257600080fd5b61417b8b613c7d565b995060208b01356001600160401b038082111561419757600080fd5b6141a38e838f01613c99565b9a5060408d01359150808211156141b957600080fd5b6141c58e838f01613aa9565b909a50985060608d01359150808211156141de57600080fd5b6141ea8e838f01613aa9565b909850965060808d013591508082111561420357600080fd5b61420f8e838f01613aa9565b909650945060a08d013591508082111561422857600080fd5b506142358d828e01613aa9565b915080935050809150509295989b9194979a5092959850565b60006020828403121561426057600080fd5b8151801515811461369857600080fd5b6000808335601e1984360301811261428757600080fd5b8301803591506001600160401b038211156142a157600080fd5b6020019150600581901b3603821315613aed57600080fd5b6000808335601e198436030181126142d057600080fd5b83016020810192503590506001600160401b038111156142ef57600080fd5b8060051b3603821315613aed57600080fd5b8183526000602080850194508260005b8581101561433f57813561432481613a4e565b6001600160a01b031687529582019590820190600101614311565b509495945050505050565b81835260006001600160fb1b0383111561436357600080fd5b8260051b80836020870137939093016020019392505050565b6000813561438981613a4e565b6001600160a01b0390811684526020830135906143a582613a4e565b90811660208501526040830135906143bc82613a4e565b16604084015260608281013590840152608082013563ffffffff811681146143e357600080fd5b63ffffffff1660808401526143fb60a08301836142b9565b60e060a086015261441060e086018284614301565b91505061442060c08401846142b9565b85830360c087015261443383828461434a565b9695505050505050565b608081526000614450608083018861437c565b8281036020848101919091528682528791810160005b8881101561449457833561447981613a4e565b6001600160a01b031682529282019290820190600101614466565b5060408501969096525050509015156060909101529392505050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156144d857600080fd5b5051919050565b602081526000613698602083018461437c565b85815260606020808301829052908201859052600090869060808401835b8881101561453e57833561452381613a4e565b6001600160a01b031682529282019290820190600101614510565b50848103604086015261455281878961434a565b9a9950505050505050505050565b8082018082111561209957612099613a80565b600081518084526020808501945080840160005b8381101561433f5781516001600160a01b031687529582019590820190600101614587565b600081518084526020808501945080840160005b8381101561433f578151875295820195908201906001016145c0565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561466857603f1989840301855281516060815181865261462982870182614573565b915050888201518582038a87015261464182826145ac565b928901516001600160a01b0316958901959095525094870194925090860190600101614603565b509098975050505050505050565b6000602080838503121561468957600080fd5b82516001600160401b0381111561469f57600080fd5b8301601f810185136146b057600080fd5b80516146be61403882613ff4565b81815260059190911b820183019083810190878311156146dd57600080fd5b928401925b828410156139a5578351825292840192908401906146e2565b8881526001600160a01b0388811660208301528781166040830152861660608201526bffffffffffffffffffffffff8516608082015260a0810184905261010060c0820181905260009061475183820186614573565b905082810360e084015261476581856145ac565b9b9a5050505050505050505050565b6000808335601e1984360301811261478b57600080fd5b83016020810192503590506001600160401b038111156147aa57600080fd5b803603821315613aed57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8035825260006147f56020830183614774565b6040602086015261480a6040860182846147b9565b95945050505050565b81835260006020808501808196508560051b810191508460005b878110156148635782840389526148448288614774565b61484f8682846147b9565b9a87019a955050509084019060010161482d565b5091979650505050505050565b81835260006020808501808196508560051b810191508460005b878110156148635782840389526148a182886142b9565b6148ac86828461434a565b9a87019a955050509084019060010161488a565b6001600160401b03891681526000602060a0818401526148e360a084018b6147e2565b8381036040850152888152899082016000805b8b81101561492657833564ffffffffff8116808214614913578384fd5b84525092840192918401916001016148f6565b5050848103606086015261493b81898b614813565b925050508281036080840152614765818587614870565b60005b8381101561496d578181015183820152602001614955565b50506000910152565b6000815180845261498e816020860160208601614952565b601f01601f19169290920160200192915050565b60018060a01b03841681526060602082015260008351604060608401526149cc60a0840182614976565b602095909501516080840152505060400152919050565b6000600160ff1b82016149f8576149f8613a80565b5060000390565b634e487b7160e01b600052602160045260246000fd5b602081526000611df36020830184866147b9565b600060208284031215614a3b57600080fd5b81516003811061369857600080fd5b606081526000614a5e6060830187896147b9565b8281036020840152614a718186886147b9565b9150508260408301529695505050505050565b600060018201614a9657614a96613a80565b5060010190565b6000823560de19833603018112614ab357600080fd5b9190910192915050565b606080825284519082018190526000906020906080840190828801845b82811015614aff5781516001600160a01b031684529284019290840190600101614ada565b50505083810382850152614b1381876145ac565b9250505060018060a01b0383166040830152949350505050565b6001600160401b038b16815260c060208201526000614b4f60c083018c6147e2565b828103604084015289815260208082019060058c901b8301018c60005b8d811015614cd557848303601f19018452368f900361017e1901823512614b9257600080fd5b8e823501614ba08182614774565b6101808652614bb4610180870182846147b9565b915050614bc46020830183614774565b8683036020880152614bd78382846147b9565b92505050614be86040830183614774565b8683036040880152614bfb8382846147b9565b92505050614c0c6060830183614774565b8683036060880152614c1f8382846147b9565b92505050614c306080830183614774565b8683036080880152614c438382846147b9565b92505050614c5360a08301613c7d565b6001600160401b031660a0860152614c6d60c08301613c7d565b6001600160401b031660c0860152614c8760e08301613c7d565b6001600160401b031660e08601526101008281013590860152610120808301359086015261014080830135908601526101609182013591909401526020938401939190910190600101614b6c565b50508481036060860152614cea818b8d614813565b925050508281036080840152614d01818789614870565b905082810360a0840152614d16818587614870565b9d9c50505050505050505050505050565b808202811582820484141761209957612099613a80565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008351614d9b818460208801614952565b6fffffffffffffffffffffffffffffffff19939093169190920190815260100192915050565b60008251614ab3818460208701614952565b602081526000613698602083018461497656fea2646970667358221220e74e8dd6fd2ac3322684e60b4a55f5aa01ec5544d2190bc01513431ce2c9241964736f6c63430008130033
Deployed Bytecode
0x6080604052600436106102065760003560e01c80636d96a2aa11610118578063d1464931116100a0578063e2c834451161006f578063e2c8344514610849578063ea4d3c9b14610869578063ec54aa7b14610889578063ec730177146108a9578063ff0996b5146108c957600080fd5b8063d1464931146107c6578063dc560c88146107dc578063dda3346c14610809578063e251ef521461082957600080fd5b8063ae2814d2116100e7578063ae2814d21461070e578063b3d4262114610723578063b915588514610763578063bc79a36514610790578063c26f2056146107a657600080fd5b80636d96a2aa1461069b5780639ebf4ab1146106bb578063a0d58d8a146106ce578063a3aae136146106ee57600080fd5b8063397bfbac1161019b578063479d39761161016a578063479d3976146105fe57806347e7ef24146106265780635299ac17146106465780635361477b14610666578063573803fb1461068657600080fd5b8063397bfbac1461058857806339b70e381461059e5780633f65cf19146105be5780634665bcda146105de57600080fd5b8063127842a4116101d7578063127842a4146104f55780631459457a1461052b57806323e481751461054b5780632e992fc51461056b57600080fd5b8062435da514610448578062cb637e146104855780630cca214f146104a55780630cd4649e146104e057600080fd5b3661044357603a546001600160a01b031633036102e457603560009054906101000a90046001600160a01b03166001600160a01b031663f617eecc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610270573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102949190613a63565b6001600160a01b0316636c0d86bd346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156102ce57600080fd5b505af11580156102e2573d6000803e3d6000fd5b005b326000908152603e602052604081205447901561031b576103036108e9565b915061030f8282613a96565b90508060000361031b57005b60355460408051633d85fbb360e21b815290516000926001600160a01b03169163f617eecc9160048083019260209291908290030181865afa158015610365573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103899190613a63565b90506000816001600160a01b03168360405160006040518083038185875af1925050503d80600081146103d8576040519150601f19603f3d011682016040523d82523d6000602084013e6103dd565b606091505b50509050806103ff576040516312171d8360e31b815260040160405180910390fd5b604080516001600160a01b0384168152602081018590527f64459fab7324199920bec86f9ce814dab17621d386f548c8a7c4e638d28fb8f4910160405180910390a1005b600080fd5b34801561045457600080fd5b50603354610468906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561049157600080fd5b506102e26104a0366004613af4565b6109bd565b3480156104b157600080fd5b506104d26104c0366004613b6b565b60416020526000908152604090205481565b60405190815260200161047c565b3480156104ec57600080fd5b506102e261125a565b34801561050157600080fd5b50610468610510366004613b84565b6036602052600090815260409020546001600160a01b031681565b34801561053757600080fd5b506102e2610546366004613ba1565b61135e565b34801561055757600080fd5b506104d2610566366004613c12565b611612565b34801561057757600080fd5b506104d26801bc16d674ec80000081565b34801561059457600080fd5b506104d2603b5481565b3480156105aa57600080fd5b50603454610468906001600160a01b031681565b3480156105ca57600080fd5b506102e26105d9366004613cb1565b611dfb565b3480156105ea57600080fd5b50603954610468906001600160a01b031681565b34801561060a57600080fd5b5061046873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b34801561063257600080fd5b506104d2610641366004613d7f565b611ff7565b34801561065257600080fd5b506102e2610661366004613dab565b61209f565b34801561067257600080fd5b506102e2610681366004613e5d565b6123a8565b34801561069257600080fd5b506104d261254f565b3480156106a757600080fd5b50603754610468906001600160a01b031681565b6102e26106c9366004613f81565b61268b565b3480156106da57600080fd5b506104d26106e9366004613b84565b61287d565b3480156106fa57600080fd5b50603a54610468906001600160a01b031681565b34801561071a57600080fd5b506102e26129b1565b34801561072f57600080fd5b5061075361073e366004613b6b565b60406020819052600091825290205460ff1681565b604051901515815260200161047c565b34801561076f57600080fd5b506104d261077e366004613b84565b603e6020526000908152604090205481565b34801561079c57600080fd5b506104d2603d5481565b3480156107b257600080fd5b506102e26107c1366004613c12565b612a9e565b3480156107d257600080fd5b506104d2603c5481565b3480156107e857600080fd5b506104d26107f7366004613b84565b603f6020526000908152604090205481565b34801561081557600080fd5b506102e2610824366004614082565b612f09565b34801561083557600080fd5b506102e2610844366004614153565b612ffd565b34801561085557600080fd5b506102e2610864366004613d7f565b613117565b34801561087557600080fd5b50603854610468906001600160a01b031681565b34801561089557600080fd5b506102e26108a4366004613b6b565b613202565b3480156108b557600080fd5b506104d26108c4366004613b84565b613301565b3480156108d557600080fd5b50603554610468906001600160a01b031681565b326000908152603e602052604081205481904710156109085747610919565b326000908152603e60205260409020545b604051909150600090329083156108fc0290849084818181858888f1935050505090508061095a576040516312171d8360e31b815260040160405180910390fd5b326000908152603e602052604081208054849290610979908490613a96565b909155505060408051328152602081018490527f667ad9c7167aea9bfcff8b321015abb0d8b77cf151a377e09e12b9017f9889fd910160405180910390a150919050565b6109c56134b1565b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa158015610a0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a31919061424e565b610a4e5760405163bcefa34f60e01b815260040160405180910390fd5b60005a9050610a6060a0860186614270565b84149050610a8157604051632b477e7160e11b815260040160405180910390fd5b6038546040516360d7faed60e01b81526001600160a01b03909116906360d7faed90610aba90889088908890889060019060040161443d565b600060405180830381600087803b158015610ad457600080fd5b505af1158015610ae8573d6000803e3d6000fd5b505050506000603560009054906101000a90046001600160a01b03166001600160a01b031663f617eecc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b659190613a63565b6001600160a01b03166351a2d6d16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ba2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc69190613a63565b905060005b84811015611179576000868683818110610be757610be76144b0565b9050602002016020810190610bfc9190613b84565b6001600160a01b031603610c235760405163862a606760e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee868683818110610c4a57610c4a6144b0565b9050602002016020810190610c5f9190613b84565b6001600160a01b031614158015610d305750603860009054906101000a90046001600160a01b03166001600160a01b0316639104c3196040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610cc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cea9190613a63565b6001600160a01b0316610d0060a0890189614270565b83818110610d1057610d106144b0565b9050602002016020810190610d259190613b84565b6001600160a01b0316145b15610d4e57604051630b049d2560e11b815260040160405180910390fd5b610d5b60c0880188614270565b82818110610d6b57610d6b6144b0565b90506020020135603f6000888885818110610d8857610d886144b0565b9050602002016020810190610d9d9190613b84565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254610dcc9190613a96565b9091555073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9050868683818110610df957610df96144b0565b9050602002016020810190610e0e9190613b84565b6001600160a01b031614611171576000826001600160a01b0316637be71216888885818110610e3f57610e3f6144b0565b9050602002016020810190610e549190613b84565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610e98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ebc91906144c6565b90506000878784818110610ed257610ed26144b0565b9050602002016020810190610ee79190613b84565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015610f2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5191906144c6565b905081156111365781811115610f675781610f69565b805b9150610f758282613a96565b9050611029603560009054906101000a90046001600160a01b03166001600160a01b031663f617eecc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff19190613a63565b838a8a87818110611004576110046144b0565b90506020020160208101906110199190613b84565b6001600160a01b0316919061350a565b603560009054906101000a90046001600160a01b03166001600160a01b031663f617eecc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561107c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a09190613a63565b6001600160a01b031663d9cd0aaa8989868181106110c0576110c06144b0565b90506020020160208101906110d59190613b84565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101859052604401600060405180830381600087803b15801561111d57600080fd5b505af1158015611131573d6000803e3d6000fd5b505050505b801561116e5761116c888885818110611151576111516144b0565b90506020020160208101906111669190613b84565b826135ea565b505b50505b600101610bcb565b50603854604051632cbd9b6d60e11b81527e31d86140cfa7fee3aca26a490f754ce3afc3c6d2ca211a94172af88ec988e2916001600160a01b03169063597b36da906111c9908a906004016144df565b602060405180830381865afa1580156111e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120a91906144c6565b61121760a0890189614270565b61122460c08b018b614270565b6040516112359594939291906144f2565b60405180910390a16112498261c35061369f565b505061125460018055565b50505050565b6112626134b1565b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa1580156112aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ce919061424e565b6112eb5760405163bcefa34f60e01b815260040160405180910390fd5b603a60009054906101000a90046001600160a01b03166001600160a01b0316630cd4649e6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561133b57600080fd5b505af115801561134f573d6000803e3d6000fd5b5050505061135c60018055565b565b600054610100900460ff161580801561137e5750600054600160ff909116105b806113985750303b158015611398575060005460ff166001145b6114005760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015611423576000805461ff0019166101001790555b6001600160a01b03861661144a5760405163862a606760e01b815260040160405180910390fd5b6001600160a01b0385166114715760405163862a606760e01b815260040160405180910390fd5b6001600160a01b0384166114985760405163862a606760e01b815260040160405180910390fd5b6001600160a01b0383166114bf5760405163862a606760e01b815260040160405180910390fd5b6001600160a01b0382166114e65760405163862a606760e01b815260040160405180910390fd5b6114ee61372f565b603380546001600160a01b038089166001600160a01b0319928316179092556034805488841690831617905560358054878416908316179055603880548684169083161790556039805492851692909116821790556040805163426c083160e11b815290516384d810629160048082019260209290919082900301816000875af1158015611580573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a49190613a63565b603a80546001600160a01b0319166001600160a01b0392909216919091179055801561160a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b600061161c6134b1565b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa158015611664573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611688919061424e565b6116a55760405163bcefa34f60e01b815260040160405180910390fd5b60005a90508483146116ca57604051632b477e7160e11b815260040160405180910390fd5b604080516001808252818301909252600091816020015b604080516060808201835280825260208201526000918101919091528152602001906001900390816116e1579050509050856001600160401b0381111561172a5761172a613def565b604051908082528060200260200182016040528015611753578160200160208202803683370190505b5081600081518110611767576117676144b0565b602090810291909101015152856001600160401b0381111561178b5761178b613def565b6040519080825280602002602001820160405280156117b4578160200160208202803683370190505b50816000815181106117c8576117c86144b0565b602090810291909101810151015260385460405163285e212160e21b81523060048201526000916001600160a01b03169063a178848490602401602060405180830381865afa15801561181f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061184391906144c6565b905060005b87811015611c955773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee898983818110611877576118776144b0565b905060200201602081019061188c9190613b84565b6001600160a01b0316036119bb57603960009054906101000a90046001600160a01b03166001600160a01b0316639104c3196040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119119190613a63565b83600081518110611924576119246144b0565b6020026020010151600001518281518110611941576119416144b0565b60200260200101906001600160a01b031690816001600160a01b031681525050868682818110611973576119736144b0565b905060200201358360008151811061198d5761198d6144b0565b60200260200101516020015182815181106119aa576119aa6144b0565b602002602001018181525050611bbe565b60006036818b8b858181106119d2576119d26144b0565b90506020020160208101906119e79190613b84565b6001600160a01b0390811682526020820192909252604001600020541603611a225760405163862a606760e01b815260040160405180910390fd5b603660008a8a84818110611a3857611a386144b0565b9050602002016020810190611a4d9190613b84565b6001600160a01b03908116825260208201929092526040016000908120548551921691859190611a7f57611a7f6144b0565b6020026020010151600001518281518110611a9c57611a9c6144b0565b60200260200101906001600160a01b031690816001600160a01b031681525050603660008a8a84818110611ad257611ad26144b0565b9050602002016020810190611ae79190613b84565b6001600160a01b0390811682526020820192909252604001600020541663e3dae51c888884818110611b1b57611b1b6144b0565b905060200201356040518263ffffffff1660e01b8152600401611b4091815260200190565b602060405180830381865afa158015611b5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b8191906144c6565b83600081518110611b9457611b946144b0565b6020026020010151602001518281518110611bb157611bb16144b0565b6020026020010181815250505b3083600081518110611bd257611bd26144b0565b6020026020010151604001906001600160a01b031690816001600160a01b03168152505082600081518110611c0957611c096144b0565b6020026020010151602001518181518110611c2657611c266144b0565b6020026020010151603f60008b8b85818110611c4457611c446144b0565b9050602002016020810190611c599190613b84565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254611c889190614560565b9091555050600101611848565b506038546040516306ec6e8160e11b81526000916001600160a01b031690630dd8dd0290611cc79086906004016145dc565b6000604051808303816000875af1158015611ce6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d0e9190810190614676565b600081518110611d2057611d206144b0565b6020908102919091018101516000818152604092839052918220805460ff1916600117905560375485519193507ff7c9db32693636e458573257dad812f58a7c5cc3067e0fad83b601b46947615a92849230926001600160a01b0316918391889143918b9190611d9257611d926144b0565b6020026020010151600001518a600081518110611db157611db16144b0565b602002602001015160200151604051611dd19897969594939291906146fb565b60405180910390a1611de58461c35061369f565b9350505050611df360018055565b949350505050565b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa158015611e43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e67919061424e565b611e845760405163bcefa34f60e01b815260040160405180910390fd5b60005a603a54604051633f65cf1960e01b81529192506001600160a01b031690633f65cf1990611ec6908c908c908c908c908c908c908c908c906004016148c0565b600060405180830381600087803b158015611ee057600080fd5b505af1158015611ef4573d6000803e3d6000fd5b5050505060005b82811015611fdf576000611f63858584818110611f1a57611f1a6144b0565b9050602002810190611f2c9190614270565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061375e92505050565b60008181526041602052604090205490915015611fa757600081815260416020526040812054603b805491929091611f9c908490613a96565b90915550611fc89050565b6801bc16d674ec800000603b6000828254611fc29190613a96565b90915550505b600090815260416020526040812055600101611efb565b50611fec81603d5461369f565b505050505050505050565b60006120016134b1565b6035546001600160a01b0316331461202c576040516342d16b8b60e11b815260040160405180910390fd5b6001600160a01b03838116600090815260366020526040902054161580612051575081155b1561206f5760405163862a606760e01b815260040160405180910390fd5b6120846001600160a01b038416333085613782565b61208e83836135ea565b905061209960018055565b92915050565b6120a76134b1565b603354604051630d5dcbef60e31b81523360048201526001600160a01b0390911690636aee5f7890602401602060405180830381865afa1580156120ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612113919061424e565b6121305760405163cbdd1d2760e01b815260040160405180910390fd5b6001600160a01b0382166121575760405163862a606760e01b815260040160405180910390fd5b6001600160a01b038116158015906122575750816001600160a01b0316816001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d69190613a63565b6001600160a01b0316141580612257575060345460405163198f077960e21b81526001600160a01b0383811660048301529091169063663c1de490602401602060405180830381865afa158015612231573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612255919061424e565b155b1561227557604051632711b74d60e11b815260040160405180910390fd5b6001600160a01b03828116600090815260366020526040902054161580159061231657506001600160a01b03828116600090815260366020526040808220549051630aa794bf60e31b81523060048201529192169063553ca5f890602401602060405180830381865afa1580156122f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061231491906144c6565b115b1561233457604051630f1fd48960e11b815260040160405180910390fd5b6001600160a01b0382811660008181526036602090815260409182902080546001600160a01b031916948616948517905581519283528201929092527f1a654dbe468f1cff27ced5a916efd4120a4155caf290688ab42aebe90554683e910160405180910390a16123a460018055565b5050565b6123b06134b1565b603354604051630d5dcbef60e31b81523360048201526001600160a01b0390911690636aee5f7890602401602060405180830381865afa1580156123f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061241c919061424e565b6124395760405163cbdd1d2760e01b815260040160405180910390fd5b6001600160a01b0383166124605760405163862a606760e01b815260040160405180910390fd5b6037546001600160a01b03161561248a57604051631c52d05d60e11b815260040160405180910390fd5b603780546001600160a01b0319166001600160a01b0385811691821790925560385460405163eea9064b60e01b815292169163eea9064b916124d291869086906004016149a2565b600060405180830381600087803b1580156124ec57600080fd5b505af1158015612500573d6000803e3d6000fd5b50506040516001600160a01b03861681527ffe608947467beb30a90e072fd2fc7d52baecf0935f542011fcd8fa6362a5d5b39250602001905060405180910390a161254a60018055565b505050565b6039546040516360f4062b60e01b815230600482015260009182916001600160a01b03909116906360f4062b90602401602060405180830381865afa15801561259c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c091906144c6565b90506000811261262657603b5473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee600052603f6020527f5d7315d061885134292236184dbffd84acd8b3aaff2ca1613d734d4448806a5a54829161261791614560565b6126219190614560565b612685565b61262f816149e3565b603b5473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee600052603f6020527f5d7315d061885134292236184dbffd84acd8b3aaff2ca1613d734d4448806a5a5461267b9190614560565b6126859190613a96565b91505090565b6035546001600160a01b031633146126b6576040516342d16b8b60e11b815260040160405180910390fd5b603a546040516358eaee7960e01b81526000916001600160a01b0316906358eaee79906126e99089908990600401614a15565b602060405180830381865afa158015612706573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061272a9190614a29565b600281111561273b5761273b6149ff565b0361280a57600061278186868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137ba92505050565b600081815260416020526040812054919250349061279f8284614560565b90506801bc16d674ec8000006127b53485614560565b11156127dd576127ce836801bc16d674ec800000613a96565b91506801bc16d674ec80000090505b6000848152604160205260408120829055603b8054849290612800908490614560565b9091555050505050505b6039546040516326d3918d60e21b81526001600160a01b0390911690639b4e46349034906128449089908990899089908990600401614a4a565b6000604051808303818588803b15801561285d57600080fd5b505af1158015612871573d6000803e3d6000fd5b50505050505050505050565b6034546040516322e2ab0f60e21b815230600482015260009182916001600160a01b0390911690638b8aac3c90602401602060405180830381865afa1580156128ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128ee91906144c6565b905060005b81811015612997576034546040516365e15eb160e11b8152306004820152602481018390526001600160a01b0386811692169063cbc2bd6290604401602060405180830381865afa15801561294c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129709190613a63565b6001600160a01b031603612985579392505050565b8061298f81614a84565b9150506128f3565b5060405163c5723b5160e01b815260040160405180910390fd5b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa1580156129f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a1d919061424e565b612a3a5760405163bcefa34f60e01b815260040160405180910390fd5b603a60009054906101000a90046001600160a01b03166001600160a01b031663baa7145a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612a8a57600080fd5b505af1158015611254573d6000803e3d6000fd5b612aa66134b1565b60335460405163bcc6ce2360e01b81523360048201526001600160a01b039091169063bcc6ce2390602401602060405180830381865afa158015612aee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b12919061424e565b612b2f57604051632efffa9d60e01b815260040160405180910390fd5b808314612b4f57604051632b477e7160e11b815260040160405180910390fd5b60005b83811015612eff576000838383818110612b6e57612b6e6144b0565b9050602002016020810190612b839190613b84565b6001600160a01b031603612baa5760405163862a606760e01b815260040160405180910390fd5b6038546000906001600160a01b031663597b36da878785818110612bd057612bd06144b0565b9050602002810190612be29190614a9d565b6040518263ffffffff1660e01b8152600401612bfe91906144df565b602060405180830381865afa158015612c1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c3f91906144c6565b60008181526040602081905290205490915060ff1615612c725760405163eb3d1dcd60e01b815260040160405180910390fd5b603854604051635bf8375f60e11b8152600481018390526001600160a01b039091169063b7f06ebe90602401602060405180830381865afa158015612cbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cdf919061424e565b612cfc576040516355780d0f60e11b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee848484818110612d2357612d236144b0565b9050602002016020810190612d389190613b84565b6001600160a01b031614158015612e2f5750603860009054906101000a90046001600160a01b03166001600160a01b0316639104c3196040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612d9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc39190613a63565b6001600160a01b0316868684818110612dde57612dde6144b0565b9050602002810190612df09190614a9d565b612dfe9060a0810190614270565b6000818110612e0f57612e0f6144b0565b9050602002016020810190612e249190613b84565b6001600160a01b0316145b15612e4d57604051630b049d2560e11b815260040160405180910390fd5b858583818110612e5f57612e5f6144b0565b9050602002810190612e719190614a9d565b612e7f9060c0810190614270565b6000818110612e9057612e906144b0565b90506020020135603f6000868686818110612ead57612ead6144b0565b9050602002016020810190612ec29190613b84565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254612ef19190614560565b909155505050600101612b52565b5061125460018055565b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa158015612f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f75919061424e565b612f925760405163bcefa34f60e01b815260040160405180910390fd5b603a54604051633768cd1b60e21b81526001600160a01b039091169063dda3346c90612fc690869086908690600401614abd565b600060405180830381600087803b158015612fe057600080fd5b505af1158015612ff4573d6000803e3d6000fd5b50505050505050565b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa158015613045573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613069919061424e565b6130865760405163bcefa34f60e01b815260040160405180910390fd5b60005a603a54604051637128f7a960e11b81529192506001600160a01b03169063e251ef52906130cc908e908e908e908e908e908e908e908e908e908e90600401614b2d565b600060405180830381600087803b1580156130e657600080fd5b505af11580156130fa573d6000803e3d6000fd5b5050505061310a81603d5461369f565b5050505050505050505050565b6033546040516358e3de6f60e01b81523360048201526001600160a01b03909116906358e3de6f90602401602060405180830381865afa15801561315f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613183919061424e565b6131a05760405163bcefa34f60e01b815260040160405180910390fd5b603a5460405163e2c8344560e01b81526001600160a01b038481166004830152602482018490529091169063e2c8344590604401600060405180830381600087803b1580156131ee57600080fd5b505af115801561160a573d6000803e3d6000fd5b61320a6134b1565b603354604051630d5dcbef60e31b81523360048201526001600160a01b0390911690636aee5f7890602401602060405180830381865afa158015613252573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613276919061424e565b6132935760405163cbdd1d2760e01b815260040160405180910390fd5b806000036132b45760405163862a606760e01b815260040160405180910390fd5b603d5460408051918252602082018390527fbfad24c5385b591e87ef890b13ebedaadf34399714ea0e2dc0f6e4ff69c731dd910160405180910390a1603d8190556132fe60018055565b50565b6001600160a01b0381166000908152603f602052604081205415613436576001600160a01b03808316600090815260366020908152604080832054603f90925291829020549151637a8b263760e01b8152921691637a8b26379161336b9160040190815260200190565b602060405180830381865afa158015613388573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133ac91906144c6565b6001600160a01b0383811660009081526036602052604090819020549051630aa794bf60e31b815230600482015291169063553ca5f890602401602060405180830381865afa158015613403573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061342791906144c6565b6134319190614560565b612099565b6001600160a01b0382811660009081526036602052604090819020549051630aa794bf60e31b815230600482015291169063553ca5f890602401602060405180830381865afa15801561348d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209991906144c6565b6002600154036135035760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016113f7565b6002600155565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa15801561355a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061357e91906144c6565b90506112548463095ea7b360e01b856135978686614560565b6040516001600160a01b03909216602483015260448201526064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261382f565b603454600090613607906001600160a01b0385811691168461350a565b6034546001600160a01b03848116600081815260366020526040908190205490516373d0285560e11b8152908316600482015260248101919091526044810185905291169063e7a050aa906064016020604051808303816000875af1158015613674573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061369891906144c6565b9392505050565b600048825a6136ae9086613a96565b6136b89190614560565b6136c29190614d27565b336000908152603e60205260408120805492935083929091906136e6908490614560565b909155505060408051338152602081018390527f4ff29a094e434f8a698185e97d3a285f4ba26c723f8ec8d2c9914213d61589ca910160405180910390a1505050565b60018055565b600054610100900460ff166137565760405162461bcd60e51b81526004016113f790614d3e565b61135c613904565b600081600081518110613773576137736144b0565b60200260200101519050919050565b6040516001600160a01b03808516602483015283166044820152606481018290526112549085906323b872dd60e01b906084016135b3565b6000600282600060801b6040516020016137d5929190614d89565b60408051601f19818403018152908290526137ef91614dc1565b602060405180830381855afa15801561380c573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061209991906144c6565b6000613884826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661392b9092919063ffffffff16565b90508051600014806138a55750808060200190518101906138a5919061424e565b61254a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016113f7565b600054610100900460ff166137295760405162461bcd60e51b81526004016113f790614d3e565b6060611df3848460008585600080866001600160a01b031685876040516139529190614dc1565b60006040518083038185875af1925050503d806000811461398f576040519150601f19603f3d011682016040523d82523d6000602084013e613994565b606091505b50915091506139a5878383876139b0565b979650505050505050565b60608315613a1f578251600003613a18576001600160a01b0385163b613a185760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016113f7565b5081611df3565b611df38383815115613a345781518083602001fd5b8060405162461bcd60e51b81526004016113f79190614dd3565b6001600160a01b03811681146132fe57600080fd5b600060208284031215613a7557600080fd5b815161369881613a4e565b634e487b7160e01b600052601160045260246000fd5b8181038181111561209957612099613a80565b60008083601f840112613abb57600080fd5b5081356001600160401b03811115613ad257600080fd5b6020830191508360208260051b8501011115613aed57600080fd5b9250929050565b60008060008060608587031215613b0a57600080fd5b84356001600160401b0380821115613b2157600080fd5b9086019060e08289031215613b3557600080fd5b90945060208601359080821115613b4b57600080fd5b50613b5887828801613aa9565b9598909750949560400135949350505050565b600060208284031215613b7d57600080fd5b5035919050565b600060208284031215613b9657600080fd5b813561369881613a4e565b600080600080600060a08688031215613bb957600080fd5b8535613bc481613a4e565b94506020860135613bd481613a4e565b93506040860135613be481613a4e565b92506060860135613bf481613a4e565b91506080860135613c0481613a4e565b809150509295509295909350565b60008060008060408587031215613c2857600080fd5b84356001600160401b0380821115613c3f57600080fd5b613c4b88838901613aa9565b90965094506020870135915080821115613c6457600080fd5b50613c7187828801613aa9565b95989497509550505050565b80356001600160401b0381168114613c9457600080fd5b919050565b600060408284031215613cab57600080fd5b50919050565b60008060008060008060008060a0898b031215613ccd57600080fd5b613cd689613c7d565b975060208901356001600160401b0380821115613cf257600080fd5b613cfe8c838d01613c99565b985060408b0135915080821115613d1457600080fd5b613d208c838d01613aa9565b909850965060608b0135915080821115613d3957600080fd5b613d458c838d01613aa9565b909650945060808b0135915080821115613d5e57600080fd5b50613d6b8b828c01613aa9565b999c989b5096995094979396929594505050565b60008060408385031215613d9257600080fd5b8235613d9d81613a4e565b946020939093013593505050565b60008060408385031215613dbe57600080fd5b8235613dc981613a4e565b91506020830135613dd981613a4e565b809150509250929050565b8035613c9481613a4e565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715613e2757613e27613def565b60405290565b604051601f8201601f191681016001600160401b0381118282101715613e5557613e55613def565b604052919050565b600080600060608486031215613e7257600080fd5b8335613e7d81613a4e565b92506020848101356001600160401b0380821115613e9a57600080fd5b9086019060408289031215613eae57600080fd5b613eb6613e05565b823582811115613ec557600080fd5b8301601f81018a13613ed657600080fd5b803583811115613ee857613ee8613def565b613efa601f8201601f19168701613e2d565b93508084528a86828401011115613f1057600080fd5b80868301878601376000908401860152509081529082013591810191909152929592945050506040919091013590565b60008083601f840112613f5257600080fd5b5081356001600160401b03811115613f6957600080fd5b602083019150836020828501011115613aed57600080fd5b600080600080600060608688031215613f9957600080fd5b85356001600160401b0380821115613fb057600080fd5b613fbc89838a01613f40565b90975095506020880135915080821115613fd557600080fd5b50613fe288828901613f40565b96999598509660400135949350505050565b60006001600160401b0382111561400d5761400d613def565b5060051b60200190565b600082601f83011261402857600080fd5b8135602061403d61403883613ff4565b613e2d565b82815260059290921b8401810191818101908684111561405c57600080fd5b8286015b848110156140775780358352918301918301614060565b509695505050505050565b60008060006060848603121561409757600080fd5b83356001600160401b03808211156140ae57600080fd5b818601915086601f8301126140c257600080fd5b813560206140d261403883613ff4565b82815260059290921b8401810191818101908a8411156140f157600080fd5b948201945b8386101561411857853561410981613a4e565b825294820194908201906140f6565b9750508701359250508082111561412e57600080fd5b5061413b86828701614017565b92505061414a60408501613de4565b90509250925092565b60008060008060008060008060008060c08b8d03121561417257600080fd5b61417b8b613c7d565b995060208b01356001600160401b038082111561419757600080fd5b6141a38e838f01613c99565b9a5060408d01359150808211156141b957600080fd5b6141c58e838f01613aa9565b909a50985060608d01359150808211156141de57600080fd5b6141ea8e838f01613aa9565b909850965060808d013591508082111561420357600080fd5b61420f8e838f01613aa9565b909650945060a08d013591508082111561422857600080fd5b506142358d828e01613aa9565b915080935050809150509295989b9194979a5092959850565b60006020828403121561426057600080fd5b8151801515811461369857600080fd5b6000808335601e1984360301811261428757600080fd5b8301803591506001600160401b038211156142a157600080fd5b6020019150600581901b3603821315613aed57600080fd5b6000808335601e198436030181126142d057600080fd5b83016020810192503590506001600160401b038111156142ef57600080fd5b8060051b3603821315613aed57600080fd5b8183526000602080850194508260005b8581101561433f57813561432481613a4e565b6001600160a01b031687529582019590820190600101614311565b509495945050505050565b81835260006001600160fb1b0383111561436357600080fd5b8260051b80836020870137939093016020019392505050565b6000813561438981613a4e565b6001600160a01b0390811684526020830135906143a582613a4e565b90811660208501526040830135906143bc82613a4e565b16604084015260608281013590840152608082013563ffffffff811681146143e357600080fd5b63ffffffff1660808401526143fb60a08301836142b9565b60e060a086015261441060e086018284614301565b91505061442060c08401846142b9565b85830360c087015261443383828461434a565b9695505050505050565b608081526000614450608083018861437c565b8281036020848101919091528682528791810160005b8881101561449457833561447981613a4e565b6001600160a01b031682529282019290820190600101614466565b5060408501969096525050509015156060909101529392505050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156144d857600080fd5b5051919050565b602081526000613698602083018461437c565b85815260606020808301829052908201859052600090869060808401835b8881101561453e57833561452381613a4e565b6001600160a01b031682529282019290820190600101614510565b50848103604086015261455281878961434a565b9a9950505050505050505050565b8082018082111561209957612099613a80565b600081518084526020808501945080840160005b8381101561433f5781516001600160a01b031687529582019590820190600101614587565b600081518084526020808501945080840160005b8381101561433f578151875295820195908201906001016145c0565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561466857603f1989840301855281516060815181865261462982870182614573565b915050888201518582038a87015261464182826145ac565b928901516001600160a01b0316958901959095525094870194925090860190600101614603565b509098975050505050505050565b6000602080838503121561468957600080fd5b82516001600160401b0381111561469f57600080fd5b8301601f810185136146b057600080fd5b80516146be61403882613ff4565b81815260059190911b820183019083810190878311156146dd57600080fd5b928401925b828410156139a5578351825292840192908401906146e2565b8881526001600160a01b0388811660208301528781166040830152861660608201526bffffffffffffffffffffffff8516608082015260a0810184905261010060c0820181905260009061475183820186614573565b905082810360e084015261476581856145ac565b9b9a5050505050505050505050565b6000808335601e1984360301811261478b57600080fd5b83016020810192503590506001600160401b038111156147aa57600080fd5b803603821315613aed57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8035825260006147f56020830183614774565b6040602086015261480a6040860182846147b9565b95945050505050565b81835260006020808501808196508560051b810191508460005b878110156148635782840389526148448288614774565b61484f8682846147b9565b9a87019a955050509084019060010161482d565b5091979650505050505050565b81835260006020808501808196508560051b810191508460005b878110156148635782840389526148a182886142b9565b6148ac86828461434a565b9a87019a955050509084019060010161488a565b6001600160401b03891681526000602060a0818401526148e360a084018b6147e2565b8381036040850152888152899082016000805b8b81101561492657833564ffffffffff8116808214614913578384fd5b84525092840192918401916001016148f6565b5050848103606086015261493b81898b614813565b925050508281036080840152614765818587614870565b60005b8381101561496d578181015183820152602001614955565b50506000910152565b6000815180845261498e816020860160208601614952565b601f01601f19169290920160200192915050565b60018060a01b03841681526060602082015260008351604060608401526149cc60a0840182614976565b602095909501516080840152505060400152919050565b6000600160ff1b82016149f8576149f8613a80565b5060000390565b634e487b7160e01b600052602160045260246000fd5b602081526000611df36020830184866147b9565b600060208284031215614a3b57600080fd5b81516003811061369857600080fd5b606081526000614a5e6060830187896147b9565b8281036020840152614a718186886147b9565b9150508260408301529695505050505050565b600060018201614a9657614a96613a80565b5060010190565b6000823560de19833603018112614ab357600080fd5b9190910192915050565b606080825284519082018190526000906020906080840190828801845b82811015614aff5781516001600160a01b031684529284019290840190600101614ada565b50505083810382850152614b1381876145ac565b9250505060018060a01b0383166040830152949350505050565b6001600160401b038b16815260c060208201526000614b4f60c083018c6147e2565b828103604084015289815260208082019060058c901b8301018c60005b8d811015614cd557848303601f19018452368f900361017e1901823512614b9257600080fd5b8e823501614ba08182614774565b6101808652614bb4610180870182846147b9565b915050614bc46020830183614774565b8683036020880152614bd78382846147b9565b92505050614be86040830183614774565b8683036040880152614bfb8382846147b9565b92505050614c0c6060830183614774565b8683036060880152614c1f8382846147b9565b92505050614c306080830183614774565b8683036080880152614c438382846147b9565b92505050614c5360a08301613c7d565b6001600160401b031660a0860152614c6d60c08301613c7d565b6001600160401b031660c0860152614c8760e08301613c7d565b6001600160401b031660e08601526101008281013590860152610120808301359086015261014080830135908601526101609182013591909401526020938401939190910190600101614b6c565b50508481036060860152614cea818b8d614813565b925050508281036080840152614d01818789614870565b905082810360a0840152614d16818587614870565b9d9c50505050505050505050505050565b808202811582820484141761209957612099613a80565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008351614d9b818460208801614952565b6fffffffffffffffffffffffffffffffff19939093169190920190815260100192915050565b60008251614ab3818460208701614952565b602081526000613698602083018461497656fea2646970667358221220e74e8dd6fd2ac3322684e60b4a55f5aa01ec5544d2190bc01513431ce2c9241964736f6c63430008130033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.