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 | 19699081 | 144 days ago | IN | 0 ETH | 0.03783738 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
NodeDelegator
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.21; import { UtilLib } from "./utils/UtilLib.sol"; import { BeaconChainProofs } from "./utils/external/BeaconChainProofs.sol"; import { TransferHelper } from "./utils/TransferHelper.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { EigenpieConstants } from "./utils/EigenpieConstants.sol"; import { EigenpieConfigRoleChecker, IEigenpieConfig } from "./utils/EigenpieConfigRoleChecker.sol"; import { INodeDelegator } from "./interfaces/INodeDelegator.sol"; import { IStrategy } from "./interfaces/eigenlayer/IStrategy.sol"; import { IDelegationManager } from "./interfaces/eigenlayer/IDelegationManager.sol"; import { IStrategyManager } from "./interfaces/eigenlayer/IStrategyManager.sol"; import { ISignatureUtils } from "./interfaces/eigenlayer/ISignatureUtils.sol"; import { IEigenPodManager, IEigenPod } from "./interfaces/eigenlayer/IEigenPodManager.sol"; import { IBeaconDepositContract } from "./interfaces/IBeaconDepositContract.sol"; import { ISSVClusters } from "./interfaces/ssvNetwork/ISSVClusters.sol"; import { ISSVNetwork } from "./interfaces/ssvNetwork/ISSVNetwork.sol"; import { ISSVNetworkCore } from "./interfaces/ssvNetwork/ISSVNetworkCore.sol"; import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; /// @title NodeDelegator Contract /// @notice The contract that handles the depositing of assets into strategies contract NodeDelegator is INodeDelegator, EigenpieConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable { using SafeERC20 for IERC20; IEigenPod public eigenPod; /// @dev Tracks the balance staked to validators and has yet to have the credentials verified with EigenLayer. /// call verifyWithdrawalCredentials to verify the validator credentials on EigenLayer uint256 public stakedButNotVerifiedEth; // operator that the Node delegator delegates to address public delegateAddress; /// @dev A mapping to track how much gas was spent by an address mapping(address => uint256) public adminGasSpentInWei; /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } fallback() external { revert InvalidCall(); } receive() external payable { address eigenStaking = eigenpieConfig.getContract(EigenpieConstants.EIGENPIE_STAKING); // If Eth from Eigenstaking, then should stay waiting to be restaked; if (msg.sender == eigenStaking) { return; } uint256 gasRefunded; address dwr = eigenpieConfig.getContract(EigenpieConstants.EIGENPIE_DWR); // If Eth from dwr, then is partial withdraw of CL reward if (msg.sender == dwr && adminGasSpentInWei[tx.origin] > 0) { gasRefunded = _refundGas(); // If no funds left, return if (msg.value == gasRefunded) { return; } } // Forward remaining balance to rewarDistributor. // Any random eth transfer to this contract will also be treated as reward. address rewarDistributor = eigenpieConfig.getContract(EigenpieConstants.EIGENPIE_REWADR_DISTRIBUTOR); TransferHelper.safeTransferETH(rewarDistributor, msg.value - gasRefunded); emit RewardsForwarded(rewarDistributor, msg.value); } /// @dev Initializes the contract /// @param eigenpieConfigAddr Eigenpie config address function initialize(address eigenpieConfigAddr) external initializer { UtilLib.checkNonZeroAddress(eigenpieConfigAddr); __Pausable_init(); __ReentrancyGuard_init(); eigenpieConfig = IEigenpieConfig(eigenpieConfigAddr); emit UpdatedEigenpieConfig(eigenpieConfigAddr); } modifier onlyEigenpieStaking() { address eigenpieStaking = eigenpieConfig.getContract(EigenpieConstants.EIGENPIE_STAKING); if (msg.sender != eigenpieStaking) revert InvalidCaller(); _; } modifier onlyWithdrawManager() { address eigenpieStaking = eigenpieConfig.getContract(EigenpieConstants.EIGENPIE_WITHDRAW_MANAGER); if (msg.sender != eigenpieStaking) revert InvalidCaller(); _; } /// @notice Fetches balance of all assets staked in eigen layer through this contract /// @return assets the assets that the node delegator has deposited into strategies and eth native staking. /// @return assetBalances the balances of the assets that the node delegator has deposited into strategies function getAssetBalances() external view override returns (address[] memory assets, uint256[] memory assetBalances) { address eigenlayerStrategyManagerAddress = eigenpieConfig.getContract(EigenpieConstants.EIGEN_STRATEGY_MANAGER); (IStrategy[] memory strategies,) = IStrategyManager(eigenlayerStrategyManagerAddress).getDeposits(address(this)); uint256 strategiesLength = strategies.length; assets = new address[](strategiesLength + 1); // LSTs and native assetBalances = new uint256[](strategiesLength + 1); // LSTs and native assets[0] = EigenpieConstants.PLATFORM_TOKEN_ADDRESS; assetBalances[0] = this.getEthBalance(); for (uint256 i = 0; i < strategiesLength;) { assets[i + 1] = address(IStrategy(strategies[i]).underlyingToken()); assetBalances[i + 1] = IStrategy(strategies[i]).userUnderlyingView(address(this)); unchecked { ++i; } } } function getEigenPod() external view returns (address) { return address(eigenPod); } /// @dev Returns the balance of an asset that the node delegator has deposited into the strategy /// @param asset the asset to get the balance of /// @return stakedBalance the balance of the asset function getAssetBalance(address asset) external view override returns (uint256) { if (UtilLib.isNativeToken(asset)) { return this.getEthBalance(); } else { address strategy = eigenpieConfig.assetStrategy(asset); if (strategy == address(0)) { return 0; } return IStrategy(strategy).userUnderlyingView(address(this)); } } /// @dev Gets the amount of ETH staked in the EigenLayer function getEthBalance() external view returns (uint256) { // TODO: Once withdrawals are enabled, allow this to handle pending withdraws IEigenPodManager eigenPodManager = IEigenPodManager(eigenpieConfig.getContract(EigenpieConstants.EIGENPOD_MANAGER)); int256 podOwnerShares = eigenPodManager.podOwnerShares(address(this)); return podOwnerShares < 0 ? stakedButNotVerifiedEth - uint256(-podOwnerShares) : stakedButNotVerifiedEth + uint256(podOwnerShares); } /// @dev Triggers stopped state. Contract must not be paused. function pause() external onlyEigenpieManager { _pause(); } /// @dev Returns to normal state. Contract must be paused function unpause() external onlyDefaultAdmin { _unpause(); } /*////////////////////////////////////////////////////////////// EigenLayer functions //////////////////////////////////////////////////////////////*/ /// @notice Approves the maximum amount of an asset to the eigen strategy manager /// @dev only supported assets can be deposited and only called by the Eigenpie manager /// @param asset the asset to deposit function maxApproveToEigenStrategyManager(address asset) external override onlySupportedAsset(asset) onlyEigenpieManager { address eigenlayerStrategyManagerAddress = eigenpieConfig.getContract(EigenpieConstants.EIGEN_STRATEGY_MANAGER); IERC20(asset).safeApprove(eigenlayerStrategyManagerAddress, type(uint256).max); } /// @notice Deposits an asset lying in this NDC into its strategy /// @dev only supported assets can be deposited and only called by the Eigenpie manager /// @param asset the asset to deposit function depositAssetIntoStrategy(address asset) external override whenNotPaused nonReentrant onlySupportedAsset(asset) onlyEigenpieManager { address strategy = eigenpieConfig.assetStrategy(asset); if (strategy == address(0)) { revert StrategyIsNotSetForAsset(); } IERC20 token = IERC20(asset); address eigenlayerStrategyManagerAddress = eigenpieConfig.getContract(EigenpieConstants.EIGEN_STRATEGY_MANAGER); uint256 balance = token.balanceOf(address(this)); emit AssetDepositIntoStrategy(asset, strategy, balance); if (balance != 0) { IStrategyManager(eigenlayerStrategyManagerAddress).depositIntoStrategy( IStrategy(strategy), token, balance ); } } /// @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 onlyEigenpieManager { UtilLib.checkNonZeroAddress(_delegateAddress); if (address(delegateAddress) != address(0x0)) revert DelegateAddressAlreadySet(); delegateAddress = _delegateAddress; address delegationManagerAddr = eigenpieConfig.getContract(EigenpieConstants.EIGEN_DELEGATION_MANAGER); IDelegationManager(delegationManagerAddr).delegateTo(delegateAddress, approverSignatureAndExpiry, approverSalt); emit DelegationAddressUpdated(_delegateAddress); } function setupValidators( DepositData calldata depositData ) external payable whenNotPaused nonReentrant onlyEigenpieManager { _makeBeaconDeposit(depositData.publicKeys, depositData.signatures, depositData.depositDataRoots); } function setupSSVNetwork( DepositData calldata depositData, SSVPayload calldata ssvPayload ) external payable whenNotPaused nonReentrant onlyEigenpieManager { _makeBeaconDeposit(depositData.publicKeys, depositData.signatures, depositData.depositDataRoots); _bulkRegisterValidator( depositData.publicKeys, ssvPayload.operatorIds, ssvPayload.sharesData, ssvPayload.amount, ssvPayload.cluster ); } /// @dev Verifies the withdrawal credentials for a withdrawal /// This will allow the EigenPodManager to verify the withdrawal credentials and credit the Node delegators with shares function verifyWithdrawalCredentials( uint64 oracleTimestamp, BeaconChainProofs.StateRootProof calldata stateRootProof, uint40[] calldata validatorIndices, bytes[] calldata withdrawalCredentialProofs, bytes32[][] calldata validatorFields ) external whenNotPaused onlyEigenpieManager { uint256 gasBefore = gasleft(); eigenPod.verifyWithdrawalCredentials( oracleTimestamp, stateRootProof, validatorIndices, withdrawalCredentialProofs, validatorFields ); // Decrement the staked but not verified ETH for (uint256 i = 0; i < validatorFields.length;) { uint64 validatorCurrentBalanceGwei = BeaconChainProofs.getEffectiveBalanceGwei( validatorFields[i] ); stakedButNotVerifiedEth -= (validatorCurrentBalanceGwei * EigenpieConstants.GWEI_TO_WEI); unchecked {++i;} } // update the gas spent for RestakeAdmin _recordGas(gasBefore); } /** * @notice Verify many Withdrawals and process them in the EigenPod * @dev For each withdrawal (partial or full), verify it in the EigenPod */ function verifyAndProcessWithdrawals( uint64 oracleTimestamp, BeaconChainProofs.StateRootProof calldata stateRootProof, BeaconChainProofs.WithdrawalProof[] calldata withdrawalProofs, bytes[] calldata validatorFieldsProofs, bytes32[][] calldata validatorFields, bytes32[][] calldata withdrawalFields ) external whenNotPaused onlyEigenpieManager { uint256 gasBefore = gasleft(); eigenPod.verifyAndProcessWithdrawals( oracleTimestamp, stateRootProof, withdrawalProofs, validatorFieldsProofs, validatorFields, withdrawalFields ); // update the gas spent for RestakeAdmin _recordGas(gasBefore); } /** * @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 whenNotPaused onlyEigenpieManager { eigenPod.withdrawNonBeaconChainETHBalanceWei(recipient, amountToWithdraw); } function queueWithdrawalToEigenLayer( address[] memory assets, uint256[] memory amounts ) external whenNotPaused nonReentrant onlyWithdrawManager { address delegationManagerAddr = eigenpieConfig.getContract(EigenpieConstants.EIGEN_DELEGATION_MANAGER); IDelegationManager.QueuedWithdrawalParams[] memory withdrawParams = new IDelegationManager.QueuedWithdrawalParams[](1); withdrawParams[0].strategies = new IStrategy[](assets.length); withdrawParams[0].shares = new uint256[](assets.length); withdrawParams[0].withdrawer = address(this); for (uint256 i = 0; i < assets.length;) { address strategy = eigenpieConfig.assetStrategy(assets[i]); withdrawParams[0].strategies[i] = IStrategy(strategy); withdrawParams[0].shares[i] = IStrategy(strategy).underlyingToShares(amounts[i]); unchecked {++i;} } bytes32[] memory withdrawalRoot = IDelegationManager(delegationManagerAddr).queueWithdrawals(withdrawParams); emit WithdrawalQueuedToEigenLayer(withdrawalRoot, withdrawParams[0].strategies, assets, amounts, block.number); } function completeAssetWithdrawalFromEigenLayer( IDelegationManager.Withdrawal calldata withdrawal, IERC20[] calldata tokens, uint256 middlewareTimesIndex, bool receiveAsTokens ) external whenNotPaused nonReentrant { uint256[] memory beforeAmounts = new uint256[](tokens.length); for (uint256 i = 0; i < tokens.length;) { beforeAmounts[i] = tokens[i].balanceOf(address(this)); unchecked {++i;} } address delegationManagerAddr = eigenpieConfig.getContract(EigenpieConstants.EIGEN_DELEGATION_MANAGER); IDelegationManager(delegationManagerAddr).completeQueuedWithdrawal( withdrawal, tokens, middlewareTimesIndex, receiveAsTokens ); address eigenpieWithdrawManager = eigenpieConfig.getContract(EigenpieConstants.EIGENPIE_WITHDRAW_MANAGER); for (uint256 i = 0; i < tokens.length;) { uint256 afterBalance = tokens[i].balanceOf(address(this)); IERC20(tokens[i]).safeTransfer(eigenpieWithdrawManager, afterBalance - beforeAmounts[i]); unchecked {++i;} } } //The DepositManager will be the pod owner in the EigenPodManager contract function createEigenPod() external override onlyDefaultAdmin { if (address(eigenPod) != address(0)) { revert EigenPodExisted(); } IEigenPodManager eigenPodManager = IEigenPodManager(eigenpieConfig.getContract(EigenpieConstants.EIGENPOD_MANAGER)); IEigenPodManager(eigenPodManager).createPod(); eigenPod = eigenPodManager.getPod(address(this)); emit EigenPodCreated(address(eigenPod)); } /*////////////////////////////////////////////////////////////// SSV Network functions //////////////////////////////////////////////////////////////*/ /// @notice Registers new validators on the SSV Network function bulkRegisterValidator( bytes[] calldata publicKeys, uint64[] calldata operatorIds, bytes[] calldata sharesData, uint256 amount, ISSVNetworkCore.Cluster memory cluster ) external onlyEigenpieManager { _bulkRegisterValidator(publicKeys, operatorIds, sharesData, amount, cluster); } /// @notice Fires the exit event for a set of validators function bulkExitValidator(bytes[] calldata publicKeys, uint64[] calldata operatorIds) external onlyEigenpieManager { address ssvNetwork = eigenpieConfig.getContract(EigenpieConstants.SSVNETWORK_ENTRY); ISSVClusters(ssvNetwork).bulkExitValidator(publicKeys, operatorIds); } /// @notice Bulk removes a set of existing validators in the same cluster from the SSV Network /// @notice Reverts if publicKeys contains duplicates or non-existent validators function bulkRemoveValidator( bytes[] calldata publicKeys, uint64[] memory operatorIds, ISSVNetworkCore.Cluster memory cluster ) external onlyEigenpieManager { address ssvNetwork = eigenpieConfig.getContract(EigenpieConstants.SSVNETWORK_ENTRY); ISSVClusters(ssvNetwork).bulkRemoveValidator(publicKeys, operatorIds, cluster); } function setFeeRecipientAddress(address feeRecipientAddress) external onlyEigenpieManager { address ssvNetwork = eigenpieConfig.getContract(EigenpieConstants.SSVNETWORK_ENTRY); ISSVNetwork(ssvNetwork).setFeeRecipientAddress(feeRecipientAddress); } function deposit(uint64[] memory operatorIds, uint256 amount, ISSVNetworkCore.Cluster memory cluster) external onlyEigenpieManager { address ssvNetwork = eigenpieConfig.getContract(EigenpieConstants.SSVNETWORK_ENTRY); ISSVClusters(ssvNetwork).deposit(address(this), operatorIds, amount, cluster); } function withdraw(uint64[] memory operatorIds, uint256 tokenAmount, ISSVNetworkCore.Cluster memory cluster) external onlyEigenpieManager { address ssvNetwork = eigenpieConfig.getContract(EigenpieConstants.SSVNETWORK_ENTRY); ISSVClusters(ssvNetwork).withdraw(operatorIds, tokenAmount, cluster); } /*////////////////////////////////////////////////////////////// Internal functions //////////////////////////////////////////////////////////////*/ /** * @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) internal { uint256 baseGasAmountSpent = eigenpieConfig.baseGasAmountSpent(); uint256 gasSpent = (initialGas - gasleft() + baseGasAmountSpent) * tx.gasprice; adminGasSpentInWei[msg.sender] += gasSpent; emit GasSpent(msg.sender, gasSpent); } /** * @notice Send owed refunds to the admin * @dev . * @return uint256 . */ function _refundGas() internal returns (uint256) { uint256 gasRefund = msg.value >= adminGasSpentInWei[tx.origin] ? adminGasSpentInWei[tx.origin] : msg.value; TransferHelper.safeTransferETH(tx.origin, gasRefund); // reset gas spent by admin adminGasSpentInWei[tx.origin] -= gasRefund; emit GasRefunded(tx.origin, gasRefund); return gasRefund; } function _eigenPodwithdrawCredential() internal returns(bytes memory) { if (address(eigenPod) == address(0)) revert EigenPodExisted(); bytes memory withdrawalCredentials = abi.encodePacked( hex'010000000000000000000000', address(eigenPod) ); return withdrawalCredentials; } function _makeBeaconDeposit( bytes[] memory publicKeys, bytes[] memory signatures, bytes32[] memory depositDataRoots ) internal { // sanity checks uint256 count = depositDataRoots.length; if (count == 0) revert AtLeastOneValidator(); if (count >= EigenpieConstants.MAX_VALIDATORS) revert MaxValidatorsInput(); if (publicKeys.length != count) revert PublicKeyNotMatch(); if (signatures.length != count) revert SignaturesNotMatch(); address depositContract = eigenpieConfig.getContract(EigenpieConstants.BEACON_DEPOSIT); bytes memory withdrawalCredentials = _eigenPodwithdrawCredential(); for (uint256 i = 0; i < count;) { IBeaconDepositContract(depositContract).deposit{ value: EigenpieConstants.DEPOSIT_AMOUNT }( publicKeys[i], withdrawalCredentials, signatures[i], depositDataRoots[i] ); unchecked {++i;} } stakedButNotVerifiedEth += count * EigenpieConstants.DEPOSIT_AMOUNT; } /// @notice Registers new validators on the SSV Network function _bulkRegisterValidator( bytes[] calldata publicKeys, uint64[] calldata operatorIds, bytes[] calldata sharesData, uint256 amount, ISSVNetworkCore.Cluster memory cluster ) internal { address ssvToken = eigenpieConfig.getContract(EigenpieConstants.SSV_TOKEN); address ssvNetwork = eigenpieConfig.getContract(EigenpieConstants.SSVNETWORK_ENTRY); IERC20(ssvToken).approve(ssvNetwork, amount); ISSVClusters(ssvNetwork).bulkRegisterValidator(publicKeys, operatorIds, sharesData, amount, cluster); } }
// 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.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal onlyInitializing { __Pausable_init_unchained(); } function __Pausable_init_unchained() internal onlyInitializing { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } /** * @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) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../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 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @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[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
// 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.0) (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. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.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.21; /** * @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.8.21; import "./IStrategy.sol"; import "./ISignatureUtils.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 { // @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); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import "../../utils/external/BeaconChainProofs.sol"; import "./IEigenPodManager.sol"; import "./IBeaconChainOracle.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.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 { 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.8.21; import "@openzeppelin/contracts/proxy/beacon/IBeacon.sol"; import "./IStrategyManager.sol"; import "./IEigenPod.sol"; import "./IBeaconChainOracle.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 { /// @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 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); 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 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: BUSL-1.1 pragma solidity 0.8.21; /** * @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.8.21; 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.8.21; import "./IStrategy.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 { /** * @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 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: UNLICENSED pragma solidity 0.8.21; /** * @title IBeaconDepositContract * @notice This is the Ethereum 2.0 deposit contract interface. * @dev Implementation can be found here: * https://github.com/ethereum/consensus-specs/blob/dev/solidity_deposit_contract/deposit_contract.sol */ interface IBeaconDepositContract { /** * @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: GPL-3.0-or-later pragma solidity 0.8.21; interface IEigenpieConfig { // Errors error ValueAlreadyInUse(); error AssetAlreadySupported(); error AssetNotSupported(); error CallerNotEigenpieConfigAdmin(); error CallerNotEigenpieConfigManager(); error CallerNotEigenpieConfigOracle(); error CallerNotEigenpieConfigOracleAdmin(); error CallerNotEigenpieConfigPriceProvider(); error CallerNotEigenpieConfigMinter(); error CallerNotEigenpieConfigBurner(); error CallerNotEigenpieConfigAllowedRole(string role); // Events event SetContract(bytes32 key, address indexed contractAddr); event AddedNewSupportedAsset(address indexed asset, address indexed receipt, uint256 depositLimit); event ReceiptTokenUpdated(address indexed asset, address indexed receipt); event RemovedSupportedAsset(address indexed asset); event AssetDepositLimitUpdate(address indexed asset, uint256 depositLimit); event AssetStrategyUpdate(address indexed asset, address indexed strategy); event AssetBoostUpdate(address indexed asset, uint256 newBoost); event ReferralUpdate(address indexed me, address indexed myReferral); // methods function baseGasAmountSpent() external returns(uint256); function assetStrategy(address asset) external view returns (address); function boostByAsset(address) external view returns (uint256); function mLRTReceiptByAsset(address) external view returns (address); function isSupportedAsset(address asset) external view returns (bool); function getContract(bytes32 contractId) external view returns (address); function getSupportedAssetList() external view returns (address[] memory); function depositLimitByAsset(address asset) external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.21; import "./eigenlayer/IStrategy.sol"; import "./ssvNetwork/ISSVNetworkCore.sol"; interface INodeDelegator { // struct struct DepositData { bytes[] publicKeys; bytes[] signatures; bytes32[] depositDataRoots; } struct SSVPayload { uint64[] operatorIds; bytes[] sharesData; uint256 amount; ISSVNetworkCore.Cluster cluster; } // event event AssetDepositIntoStrategy(address indexed asset, address indexed strategy, uint256 depositAmount); event EigenPodCreated(address indexed createdEigenPod); event RewardsForwarded(address indexed destinatino, uint256 amount); event WithdrawalQueuedToEigenLayer( bytes32[] withdrawalRoot, IStrategy[] strategies, address[] assets, uint256[] withdrawalAmounts, uint256 startBlock ); event DelegationAddressUpdated(address delegate); event GasSpent(address indexed spender, uint256 gasUsed); event GasRefunded(address indexed receiver, uint256 gasRefund); // errors error TokenTransferFailed(); error StrategyIsNotSetForAsset(); error NoPubKeysProvided(); error EigenPodExisted(); error InvalidCall(); error InvalidCaller(); error AtLeastOneValidator(); error MaxValidatorsInput(); error PublicKeyNotMatch(); error SignaturesNotMatch(); error DelegateAddressAlreadySet(); // methods function depositAssetIntoStrategy(address asset) external; function maxApproveToEigenStrategyManager(address asset) external; function getAssetBalances() external view returns (address[] memory, uint256[] memory); function getAssetBalance(address asset) external view returns (uint256); function getEthBalance() external view returns (uint256); function createEigenPod() external; function queueWithdrawalToEigenLayer( address[] memory assets, uint256[] memory amount ) external; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.21; import "./ISSVNetworkCore.sol"; interface ISSVClusters is ISSVNetworkCore { /// @notice Registers a new validator on the SSV Network /// @param publicKey The public key of the new validator /// @param operatorIds Array of IDs of operators managing this validator /// @param sharesData Encrypted shares related to the new validator /// @param amount Amount of SSV tokens to be deposited /// @param cluster Cluster to be used with the new validator function registerValidator( bytes calldata publicKey, uint64[] memory operatorIds, bytes calldata sharesData, uint256 amount, Cluster memory cluster ) external; /// @notice Registers new validators on the SSV Network /// @param publicKeys The public keys of the new validators /// @param operatorIds Array of IDs of operators managing this validator /// @param sharesData Encrypted shares related to the new validators /// @param amount Amount of SSV tokens to be deposited /// @param cluster Cluster to be used with the new validator function bulkRegisterValidator( bytes[] calldata publicKeys, uint64[] memory operatorIds, bytes[] calldata sharesData, uint256 amount, Cluster memory cluster ) external; /// @notice Removes an existing validator from the SSV Network /// @param publicKey The public key of the validator to be removed /// @param operatorIds Array of IDs of operators managing the validator /// @param cluster Cluster associated with the validator function removeValidator(bytes calldata publicKey, uint64[] memory operatorIds, Cluster memory cluster) external; /// @notice Bulk removes a set of existing validators in the same cluster from the SSV Network /// @notice Reverts if publicKeys contains duplicates or non-existent validators /// @param publicKeys The public keys of the validators to be removed /// @param operatorIds Array of IDs of operators managing the validator /// @param cluster Cluster associated with the validator function bulkRemoveValidator( bytes[] calldata publicKeys, uint64[] memory operatorIds, Cluster memory cluster ) external; /**************************/ /* Cluster External Functions */ /**************************/ /// @notice Liquidates a cluster /// @param owner The owner of the cluster /// @param operatorIds Array of IDs of operators managing the cluster /// @param cluster Cluster to be liquidated function liquidate(address owner, uint64[] memory operatorIds, Cluster memory cluster) external; /// @notice Reactivates a cluster /// @param operatorIds Array of IDs of operators managing the cluster /// @param amount Amount of SSV tokens to be deposited for reactivation /// @param cluster Cluster to be reactivated function reactivate(uint64[] memory operatorIds, uint256 amount, Cluster memory cluster) external; /******************************/ /* Balance External Functions */ /******************************/ /// @notice Deposits tokens into a cluster /// @param owner The owner of the cluster /// @param operatorIds Array of IDs of operators managing the cluster /// @param amount Amount of SSV tokens to be deposited /// @param cluster Cluster where the deposit will be made function deposit(address owner, uint64[] memory operatorIds, uint256 amount, Cluster memory cluster) external; /// @notice Withdraws tokens from a cluster /// @param operatorIds Array of IDs of operators managing the cluster /// @param tokenAmount Amount of SSV tokens to be withdrawn /// @param cluster Cluster where the withdrawal will be made function withdraw(uint64[] memory operatorIds, uint256 tokenAmount, Cluster memory cluster) external; /// @notice Fires the exit event for a validator /// @param publicKey The public key of the validator to be exited /// @param operatorIds Array of IDs of operators managing the validator function exitValidator(bytes calldata publicKey, uint64[] calldata operatorIds) external; /// @notice Fires the exit event for a set of validators /// @param publicKeys The public keys of the validators to be exited /// @param operatorIds Array of IDs of operators managing the validators function bulkExitValidator(bytes[] calldata publicKeys, uint64[] calldata operatorIds) external; /** * @dev Emitted when the validator has been added. * @param publicKey The public key of a validator. * @param operatorIds The operator ids list. * @param shares snappy compressed shares(a set of encrypted and public shares). * @param cluster All the cluster data. */ event ValidatorAdded(address indexed owner, uint64[] operatorIds, bytes publicKey, bytes shares, Cluster cluster); /** * @dev Emitted when the validator is removed. * @param publicKey The public key of a validator. * @param operatorIds The operator ids list. * @param cluster All the cluster data. */ event ValidatorRemoved(address indexed owner, uint64[] operatorIds, bytes publicKey, Cluster cluster); /** * @dev Emitted when a cluster is liquidated. * @param owner The owner of the liquidated cluster. * @param operatorIds The operator IDs managing the cluster. * @param cluster The liquidated cluster data. */ event ClusterLiquidated(address indexed owner, uint64[] operatorIds, Cluster cluster); /** * @dev Emitted when a cluster is reactivated. * @param owner The owner of the reactivated cluster. * @param operatorIds The operator IDs managing the cluster. * @param cluster The reactivated cluster data. */ event ClusterReactivated(address indexed owner, uint64[] operatorIds, Cluster cluster); /** * @dev Emitted when tokens are withdrawn from a cluster. * @param owner The owner of the cluster. * @param operatorIds The operator IDs managing the cluster. * @param value The amount of tokens withdrawn. * @param cluster The cluster from which tokens were withdrawn. */ event ClusterWithdrawn(address indexed owner, uint64[] operatorIds, uint256 value, Cluster cluster); /** * @dev Emitted when tokens are deposited into a cluster. * @param owner The owner of the cluster. * @param operatorIds The operator IDs managing the cluster. * @param value The amount of SSV tokens deposited. * @param cluster The cluster into which SSV tokens were deposited. */ event ClusterDeposited(address indexed owner, uint64[] operatorIds, uint256 value, Cluster cluster); /** * @dev Emitted when a validator begins the exit process. * @param owner The owner of the exiting validator. * @param operatorIds The operator IDs managing the validator. * @param publicKey The public key of the exiting validator. */ event ValidatorExited(address indexed owner, uint64[] operatorIds, bytes publicKey); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.21; interface ISSVNetwork { function setFeeRecipientAddress(address feeRecipientAddress) external; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.21; interface ISSVNetworkCore { /***********/ /* Structs */ /***********/ /// @notice Represents a snapshot of an operator's or a DAO's state at a certain block struct Snapshot { /// @dev The block number when the snapshot was taken uint32 block; /// @dev The last index calculated by the formula index += (currentBlock - block) * fee uint64 index; /// @dev Total accumulated earnings calculated by the formula accumulated + lastIndex * validatorCount uint64 balance; } /// @notice Represents an SSV operator struct Operator { /// @dev The number of validators associated with this operator uint32 validatorCount; /// @dev The fee charged by the operator, set to zero for private operators and cannot be increased once set uint64 fee; /// @dev The address of the operator's owner address owner; /// @dev Whitelisted flag for this operator bool whitelisted; /// @dev The state snapshot of the operator Snapshot snapshot; } /// @notice Represents a request to change an operator's fee struct OperatorFeeChangeRequest { /// @dev The new fee proposed by the operator uint64 fee; /// @dev The time when the approval period for the fee change begins uint64 approvalBeginTime; /// @dev The time when the approval period for the fee change ends uint64 approvalEndTime; } /// @notice Represents a cluster of validators struct Cluster { /// @dev The number of validators in the cluster uint32 validatorCount; /// @dev The index of network fees related to this cluster uint64 networkFeeIndex; /// @dev The last index calculated for the cluster uint64 index; /// @dev Flag indicating whether the cluster is active bool active; /// @dev The balance of the cluster uint256 balance; } /**********/ /* Errors */ /**********/ error CallerNotOwner(); // 0x5cd83192 error CallerNotWhitelisted(); // 0x8c6e5d71 error FeeTooLow(); // 0x732f9413 error FeeExceedsIncreaseLimit(); // 0x958065d9 error NoFeeDeclared(); // 0x1d226c30 error ApprovalNotWithinTimeframe(); // 0x97e4b518 error OperatorDoesNotExist(); // 0x961e3e8c error InsufficientBalance(); // 0xf4d678b8 error ValidatorDoesNotExist(); // 0xe51315d2 error ClusterNotLiquidatable(); // 0x60300a8d error InvalidPublicKeyLength(); // 0x637297a4 error InvalidOperatorIdsLength(); // 0x38186224 error ClusterAlreadyEnabled(); // 0x3babafd2 error ClusterIsLiquidated(); // 0x95a0cf33 error ClusterDoesNotExists(); // 0x185e2b16 error IncorrectClusterState(); // 0x12e04c87 error UnsortedOperatorsList(); // 0xdd020e25 error NewBlockPeriodIsBelowMinimum(); // 0x6e6c9cac error ExceedValidatorLimit(); // 0x6df5ab76 error TokenTransferFailed(); // 0x045c4b02 error SameFeeChangeNotAllowed(); // 0xc81272f8 error FeeIncreaseNotAllowed(); // 0x410a2b6c error NotAuthorized(); // 0xea8e4eb5 error OperatorsListNotUnique(); // 0xa5a1ff5d error OperatorAlreadyExists(); // 0x289c9494 error TargetModuleDoesNotExist(); // 0x8f9195fb error MaxValueExceeded(); // 0x91aa3017 error FeeTooHigh(); // 0xcd4e6167 error PublicKeysSharesLengthMismatch(); // 0x9ad467b8 error IncorrectValidatorStateWithData(bytes publicKey); // 0x89307938 error ValidatorAlreadyExistsWithData(bytes publicKey); // 0x388e7999 // legacy errors error ValidatorAlreadyExists(); // 0x8d09a73e error IncorrectValidatorState(); // 0x2feda3c1 }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.21; import { UtilLib } from "./UtilLib.sol"; import { EigenpieConstants } from "./EigenpieConstants.sol"; import { IEigenpieConfig } from "../interfaces/IEigenpieConfig.sol"; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; /// @title EigenpieConfigRoleChecker - Eigenpie Config Role Checker Contract /// @notice Handles Eigenpie config role checks abstract contract EigenpieConfigRoleChecker { IEigenpieConfig public eigenpieConfig; uint256[49] private __gap; // reserve for upgrade // events event UpdatedEigenpieConfig(address indexed eigenpieConfig); // modifiers modifier onlyRole(bytes32 role) { if (!IAccessControl(address(eigenpieConfig)).hasRole(role, msg.sender)) { string memory roleStr = string(abi.encodePacked(role)); revert IEigenpieConfig.CallerNotEigenpieConfigAllowedRole(roleStr); } _; } modifier onlyEigenpieManager() { if (!IAccessControl(address(eigenpieConfig)).hasRole(EigenpieConstants.MANAGER, msg.sender)) { revert IEigenpieConfig.CallerNotEigenpieConfigManager(); } _; } modifier onlyPriceProvider() { if (!IAccessControl(address(eigenpieConfig)).hasRole(EigenpieConstants.PRICE_PROVIDER_ROLE, msg.sender)) { revert IEigenpieConfig.CallerNotEigenpieConfigPriceProvider(); } _; } modifier onlyDefaultAdmin() { if (!IAccessControl(address(eigenpieConfig)).hasRole(EigenpieConstants.DEFAULT_ADMIN_ROLE, msg.sender)) { revert IEigenpieConfig.CallerNotEigenpieConfigAdmin(); } _; } modifier onlyOracleAdmin() { if (!IAccessControl(address(eigenpieConfig)).hasRole(EigenpieConstants.ORACLE_ADMIN_ROLE, msg.sender)) { revert IEigenpieConfig.CallerNotEigenpieConfigOracleAdmin(); } _; } modifier onlyOracle() { if (!IAccessControl(address(eigenpieConfig)).hasRole(EigenpieConstants.ORACLE_ROLE, msg.sender)) { revert IEigenpieConfig.CallerNotEigenpieConfigOracle(); } _; } modifier onlyMinter() { if (!IAccessControl(address(eigenpieConfig)).hasRole(EigenpieConstants.MINTER_ROLE, msg.sender)) { revert IEigenpieConfig.CallerNotEigenpieConfigMinter(); } _; } modifier onlyBurner() { if (!IAccessControl(address(eigenpieConfig)).hasRole(EigenpieConstants.BURNER_ROLE, msg.sender)) { revert IEigenpieConfig.CallerNotEigenpieConfigBurner(); } _; } modifier onlySupportedAsset(address asset) { if (!eigenpieConfig.isSupportedAsset(asset)) { revert IEigenpieConfig.AssetNotSupported(); } _; } // setters /// @notice Updates the Eigenpie config contract /// @dev only callable by Eigenpie default /// @param eigenpieConfigAddr the new Eigenpie config contract Address function updateEigenpieConfig(address eigenpieConfigAddr) external virtual onlyDefaultAdmin { UtilLib.checkNonZeroAddress(eigenpieConfigAddr); eigenpieConfig = IEigenpieConfig(eigenpieConfigAddr); emit UpdatedEigenpieConfig(eigenpieConfigAddr); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.21; library EigenpieConstants { //contracts bytes32 public constant EIGENPIE_STAKING = keccak256("EIGENPIE_STAKING"); bytes32 public constant EIGEN_STRATEGY_MANAGER = keccak256("EIGEN_STRATEGY_MANAGER"); bytes32 public constant EIGEN_DELEGATION_MANAGER = keccak256("EIGEN_DELEGATION_MANAGER"); bytes32 public constant PRICE_PROVIDER = keccak256("PRICE_PROVIDER"); bytes32 public constant BEACON_DEPOSIT = keccak256("BEACON_DEPOSIT"); bytes32 public constant EIGENPOD_MANAGER = keccak256("EIGENPOD_MANAGER"); bytes32 public constant EIGENPIE_PREDEPOSITHELPER = keccak256("EIGENPIE_PREDEPOSITHELPER"); bytes32 public constant EIGENPIE_REWADR_DISTRIBUTOR = keccak256("EIGENPIE_REWADR_DISTRIBUTOR"); bytes32 public constant EIGENPIE_DWR = keccak256("EIGENPIE_DWR"); bytes32 public constant SSVNETWORK_ENTRY = keccak256("SSVNETWORK_ENTRY"); bytes32 public constant SSV_TOKEN = keccak256("SSV_TOKEN"); //Roles bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; bytes32 public constant MANAGER = keccak256("MANAGER"); bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); bytes32 public constant ORACLE_ROLE = keccak256("ORACLE_ROLE"); bytes32 public constant ORACLE_ADMIN_ROLE = keccak256("ORACLE_ADMIN_ROLE"); bytes32 public constant PRICE_PROVIDER_ROLE = keccak256("PRICE_PROVIDER_ROLE"); // For Native Restaking uint256 constant PUBKEY_LENGTH = 48; uint256 constant SIGNATURE_LENGTH = 96; uint256 constant MAX_VALIDATORS = 100; uint256 constant DEPOSIT_AMOUNT = 32 ether; uint256 constant GWEI_TO_WEI = 1e9; uint256 public constant DENOMINATOR = 10_000; address public constant PLATFORM_TOKEN_ADDRESS = 0xeFEfeFEfeFeFEFEFEfefeFeFefEfEfEfeFEFEFEf; bytes32 public constant EIGENPIE_WITHDRAW_MANAGER = keccak256("EIGENPIE_WITHDRAW_MANAGER"); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import "./Merkle.sol"; import "./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.21; 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.21; /** * @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: MIT pragma solidity 0.8.21; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./UtilLib.sol"; library TransferHelper { using UtilLib for address; function safeTransferToken(address token, address to, uint256 value) internal { if (token.isNativeToken()) { safeTransferETH(to, value); } else { safeTransfer(IERC20(token), to, value); } } function safeTransferETH(address to, uint256 value) internal { (bool success,) = address(to).call{ value: value }(""); require(success, "TransferHelper: Sending ETH failed"); } function balanceOf(address token, address addr) internal view returns (uint256) { if (token.isNativeToken()) { return addr.balance; } else { return IERC20(token).balanceOf(addr); } } function safeTransfer(IERC20 token, address to, uint256 value) internal { // bytes4(keccak256(bytes('transfer(address,uint256)'))) -> 0xa9059cbb (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(0xa9059cbb, to, value)); require( success && (data.length == 0 || abi.decode(data, (bool))), "TransferHelper::safeTransfer: transfer failed" ); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))) -> 0x23b872dd (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(0x23b872dd, from, to, value)); require( success && (data.length == 0 || abi.decode(data, (bool))), "TransferHelper::safeTransferFrom: transfer failed" ); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.21; import { EigenpieConstants } from "./EigenpieConstants.sol"; /// @title UtilLib - Utility library /// @notice Utility functions library UtilLib { error ZeroAddressNotAllowed(); /// @dev zero address check modifier /// @param address_ address to check function checkNonZeroAddress(address address_) internal pure { if (address_ == address(0)) revert ZeroAddressNotAllowed(); } function isNativeToken(address addr) internal pure returns (bool) { return addr == EigenpieConstants.PLATFORM_TOKEN_ADDRESS; } }
{ "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AssetNotSupported","type":"error"},{"inputs":[],"name":"AtLeastOneValidator","type":"error"},{"inputs":[],"name":"CallerNotEigenpieConfigAdmin","type":"error"},{"inputs":[],"name":"CallerNotEigenpieConfigManager","type":"error"},{"inputs":[],"name":"DelegateAddressAlreadySet","type":"error"},{"inputs":[],"name":"EigenPodExisted","type":"error"},{"inputs":[],"name":"InvalidCall","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"MaxValidatorsInput","type":"error"},{"inputs":[],"name":"NoPubKeysProvided","type":"error"},{"inputs":[],"name":"PublicKeyNotMatch","type":"error"},{"inputs":[],"name":"SignaturesNotMatch","type":"error"},{"inputs":[],"name":"StrategyIsNotSetForAsset","type":"error"},{"inputs":[],"name":"TokenTransferFailed","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositAmount","type":"uint256"}],"name":"AssetDepositIntoStrategy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"delegate","type":"address"}],"name":"DelegationAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"createdEigenPod","type":"address"}],"name":"EigenPodCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"gasRefund","type":"uint256"}],"name":"GasRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"gasUsed","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":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"destinatino","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsForwarded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"eigenpieConfig","type":"address"}],"name":"UpdatedEigenpieConfig","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":"address[]","name":"assets","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"withdrawalAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"startBlock","type":"uint256"}],"name":"WithdrawalQueuedToEigenLayer","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"adminGasSpentInWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"publicKeys","type":"bytes[]"},{"internalType":"uint64[]","name":"operatorIds","type":"uint64[]"}],"name":"bulkExitValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"publicKeys","type":"bytes[]"},{"internalType":"uint64[]","name":"operatorIds","type":"uint64[]"},{"internalType":"bytes[]","name":"sharesData","type":"bytes[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"uint32","name":"validatorCount","type":"uint32"},{"internalType":"uint64","name":"networkFeeIndex","type":"uint64"},{"internalType":"uint64","name":"index","type":"uint64"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint256","name":"balance","type":"uint256"}],"internalType":"struct ISSVNetworkCore.Cluster","name":"cluster","type":"tuple"}],"name":"bulkRegisterValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"publicKeys","type":"bytes[]"},{"internalType":"uint64[]","name":"operatorIds","type":"uint64[]"},{"components":[{"internalType":"uint32","name":"validatorCount","type":"uint32"},{"internalType":"uint64","name":"networkFeeIndex","type":"uint64"},{"internalType":"uint64","name":"index","type":"uint64"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint256","name":"balance","type":"uint256"}],"internalType":"struct ISSVNetworkCore.Cluster","name":"cluster","type":"tuple"}],"name":"bulkRemoveValidator","outputs":[],"stateMutability":"nonpayable","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"},{"internalType":"bool","name":"receiveAsTokens","type":"bool"}],"name":"completeAssetWithdrawalFromEigenLayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"createEigenPod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delegateAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64[]","name":"operatorIds","type":"uint64[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"uint32","name":"validatorCount","type":"uint32"},{"internalType":"uint64","name":"networkFeeIndex","type":"uint64"},{"internalType":"uint64","name":"index","type":"uint64"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint256","name":"balance","type":"uint256"}],"internalType":"struct ISSVNetworkCore.Cluster","name":"cluster","type":"tuple"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"depositAssetIntoStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eigenPod","outputs":[{"internalType":"contract IEigenPod","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eigenpieConfig","outputs":[{"internalType":"contract IEigenpieConfig","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getAssetBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAssetBalances","outputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256[]","name":"assetBalances","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEigenPod","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEthBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"eigenpieConfigAddr","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"maxApproveToEigenStrategyManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"queueWithdrawalToEigenLayer","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":"address","name":"feeRecipientAddress","type":"address"}],"name":"setFeeRecipientAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes[]","name":"publicKeys","type":"bytes[]"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"},{"internalType":"bytes32[]","name":"depositDataRoots","type":"bytes32[]"}],"internalType":"struct INodeDelegator.DepositData","name":"depositData","type":"tuple"},{"components":[{"internalType":"uint64[]","name":"operatorIds","type":"uint64[]"},{"internalType":"bytes[]","name":"sharesData","type":"bytes[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"uint32","name":"validatorCount","type":"uint32"},{"internalType":"uint64","name":"networkFeeIndex","type":"uint64"},{"internalType":"uint64","name":"index","type":"uint64"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint256","name":"balance","type":"uint256"}],"internalType":"struct ISSVNetworkCore.Cluster","name":"cluster","type":"tuple"}],"internalType":"struct INodeDelegator.SSVPayload","name":"ssvPayload","type":"tuple"}],"name":"setupSSVNetwork","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes[]","name":"publicKeys","type":"bytes[]"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"},{"internalType":"bytes32[]","name":"depositDataRoots","type":"bytes32[]"}],"internalType":"struct INodeDelegator.DepositData","name":"depositData","type":"tuple"}],"name":"setupValidators","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"stakedButNotVerifiedEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"eigenpieConfigAddr","type":"address"}],"name":"updateEigenpieConfig","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"},{"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":"uint64[]","name":"operatorIds","type":"uint64[]"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"components":[{"internalType":"uint32","name":"validatorCount","type":"uint32"},{"internalType":"uint64","name":"networkFeeIndex","type":"uint64"},{"internalType":"uint64","name":"index","type":"uint64"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint256","name":"balance","type":"uint256"}],"internalType":"struct ISSVNetworkCore.Cluster","name":"cluster","type":"tuple"}],"name":"withdraw","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
60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b603254610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60325460ff90811614620000e1576032805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61592780620000f36000396000f3fe6080604052600436106101dc5760003560e01c80636794bab211610102578063b915588511610095578063e251ef5211610064578063e251ef52146107bb578063e2c83445146107db578063e4688af8146107fb578063f602e3c51461081b57610436565b8063b915588514610730578063bcbb073a1461075d578063c4d66de81461077b578063dbcdc2cc1461079b57610436565b806370ed0ada116100d157806370ed0ada146106c65780638456cb59146106db57806390fa64a0146106f0578063a3aae1361461071057610436565b80636794bab21461062e578063686e682c1461064e5780636d96a2aa1461066e5780636ffb1ba4146106a657610436565b8063397bfbac1161017a5780635361477b116101495780635361477b146105ab5780635373433f146105cb5780635aed1142146105eb5780635c975abb1461060b57610436565b8063397bfbac146105325780633f4ba83a146105565780633f65cf191461056b5780634798c72b1461058b57610436565b8063286ebd72116101b6578063286ebd72146104b35780632acd560a146104d3578063308dade1146104e657806332afd02f1461051257610436565b80630b10b2011461045c578063176b8b261461047357806322f18bf51461049357610436565b366104365760008054604051631c2d8fb360e31b81527f85629789f35d2cd1a0bb05ebf682211d7611abccda6936d07ccced33f40f293660048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa15801561024a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061026e9190614142565b90506001600160a01b038116330361028257005b60008054604051631c2d8fb360e31b81527fae657eecc2cff849e04b7d2cd73b1b0ec9d31e6e02d73c01e68bf716cf6ae2df600482015282916001600160a01b03169063e16c7d9890602401602060405180830381865afa1580156102eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061030f9190614142565b9050336001600160a01b038216148015610337575032600090815260cc602052604090205415155b1561034f5761034461082e565b915081340361034f57005b60008054604051631c2d8fb360e31b81527f4fa92c822d2e7cfdeb04f7ee17bf84c1e7d1ada8cdd71157b5bab36def2b904360048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa1580156103b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103dc9190614142565b90506103f1816103ec8534614175565b6108c8565b806001600160a01b03167f64459fab7324199920bec86f9ce814dab17621d386f548c8a7c4e638d28fb8f43460405161042c91815260200190565b60405180910390a2005b34801561044257600080fd5b5060405163574b16a760e11b815260040160405180910390fd5b34801561046857600080fd5b50610471610980565b005b34801561047f57600080fd5b5061047161048e366004614267565b610be1565b34801561049f57600080fd5b506104716104ae366004614437565b611134565b3480156104bf57600080fd5b506104716104ce3660046144eb565b6111ec565b6104716104e1366004614592565b6115a7565b3480156104f257600080fd5b506104fb61170f565b604051610509929190614671565b60405180910390f35b34801561051e57600080fd5b5061047161052d36600461469f565b611aff565b34801561053e57600080fd5b5061054860ca5481565b604051908152602001610509565b34801561056257600080fd5b50610471611c86565b34801561057757600080fd5b5061047161058636600461471c565b611d20565b34801561059757600080fd5b506104716105a63660046147ea565b611ee7565b3480156105b757600080fd5b506104716105c6366004614876565b612298565b3480156105d757600080fd5b506105486105e63660046147ea565b6124c7565b3480156105f757600080fd5b50610471610606366004614982565b612651565b34801561061757600080fd5b5060655460ff166040519015158152602001610509565b34801561063a57600080fd5b506104716106493660046147ea565b61279f565b34801561065a57600080fd5b506104716106693660046149fc565b612880565b34801561067a57600080fd5b5060cb5461068e906001600160a01b031681565b6040516001600160a01b039091168152602001610509565b3480156106b257600080fd5b506104716106c13660046147ea565b6129fa565b3480156106d257600080fd5b50610548612bc8565b3480156106e757600080fd5b50610471612cfd565b3480156106fc57600080fd5b5060005461068e906001600160a01b031681565b34801561071c57600080fd5b5060c95461068e906001600160a01b031681565b34801561073c57600080fd5b5061054861074b3660046147ea565b60cc6020526000908152604090205481565b34801561076957600080fd5b5060c9546001600160a01b031661068e565b34801561078757600080fd5b506104716107963660046147ea565b612da3565b3480156107a757600080fd5b506104716107b63660046147ea565b612f0a565b3480156107c757600080fd5b506104716107d6366004614a53565b613087565b3480156107e757600080fd5b506104716107f6366004614b4e565b6131bb565b34801561080757600080fd5b506104716108163660046149fc565b61329a565b610471610829366004614b7a565b6133e8565b32600090815260cc6020526040812054819034101561084d573461085e565b32600090815260cc60205260409020545b905061086a32826108c8565b32600090815260cc602052604081208054839290610889908490614175565b909155505060405181815232907f667ad9c7167aea9bfcff8b321015abb0d8b77cf151a377e09e12b9017f9889fd9060200160405180910390a2919050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114610915576040519150601f19603f3d011682016040523d82523d6000602084013e61091a565b606091505b505090508061097b5760405162461bcd60e51b815260206004820152602260248201527f5472616e7366657248656c7065723a2053656e64696e6720455448206661696c604482015261195960f21b60648201526084015b60405180910390fd5b505050565b60008054604051632474521560e21b81526001600160a01b03909116916391d14854916109b291903390600401614bae565b602060405180830381865afa1580156109cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f39190614bc5565b610a105760405163bda7a53b60e01b815260040160405180910390fd5b60c9546001600160a01b031615610a3a5760405163104de63b60e21b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81527f91904e667b918675a21f3da9d7cac3d4f6722c61ff157d917504d0ff0bcab7ce60048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015610aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac79190614142565b9050806001600160a01b03166384d810626040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610b09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2d9190614142565b5060405163a38406a360e01b81523060048201526001600160a01b0382169063a38406a390602401602060405180830381865afa158015610b72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b969190614142565b60c980546001600160a01b0319166001600160a01b039290921691821790556040517f651d255d6325a0e4d1ff00e7f971fa4ce4cd9d3d43f3be930670471ed88bf85190600090a250565b610be96134d9565b610bf161351f565b60008054604051631c2d8fb360e31b81527f9973d563e0c2a72196abd7bd620610c30e4e5455956b224d9c2e14b723a3f52060048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015610c5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7e9190614142565b9050336001600160a01b03821614610ca9576040516348f5c3ed60e01b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81527fe6f126e6caa9e3ecec885b4018b5fc7b4be7215ed294516a21548156199de5b560048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015610d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d369190614142565b60408051600180825281830190925291925060009190816020015b60408051606080820183528082526020820152600091810191909152815260200190600190039081610d5157905050905084516001600160401b03811115610d9b57610d9b614188565b604051908082528060200260200182016040528015610dc4578160200160208202803683370190505b5081600081518110610dd857610dd8614be2565b60209081029190910101515284516001600160401b03811115610dfd57610dfd614188565b604051908082528060200260200182016040528015610e26578160200160208202803683370190505b5081600081518110610e3a57610e3a614be2565b6020026020010151602001819052503081600081518110610e5d57610e5d614be2565b6020026020010151604001906001600160a01b031690816001600160a01b03168152505060005b855181101561104c576000805487516001600160a01b03909116906397ef9d9890899085908110610eb757610eb7614be2565b60200260200101516040518263ffffffff1660e01b8152600401610eea91906001600160a01b0391909116815260200190565b602060405180830381865afa158015610f07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2b9190614142565b90508083600081518110610f4157610f41614be2565b6020026020010151600001518381518110610f5e57610f5e614be2565b60200260200101906001600160a01b031690816001600160a01b031681525050806001600160a01b0316638c871019878481518110610f9f57610f9f614be2565b60200260200101516040518263ffffffff1660e01b8152600401610fc591815260200190565b6020604051808303816000875af1158015610fe4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110089190614bf8565b8360008151811061101b5761101b614be2565b602002602001015160200151838151811061103857611038614be2565b602090810291909101015250600101610e84565b506040516306ec6e8160e11b81526000906001600160a01b03841690630dd8dd029061107c908590600401614c11565b6000604051808303816000875af115801561109b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526110c39190810190614cab565b90507f203473145f3c567591d6c037fed4bb64bab015c4bf448d0fa16f2e562938e97881836000815181106110fa576110fa614be2565b60200260200101516000015188884360405161111a959493929190614d30565b60405180910390a1505050506111306001609755565b5050565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490611174906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015611191573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b59190614bc5565b6111d25760405163d519ed8560e01b815260040160405180910390fd5b6111e2888888888888888861357f565b5050505050505050565b6111f46134d9565b6111fc61351f565b6000836001600160401b0381111561121657611216614188565b60405190808252806020026020018201604052801561123f578160200160208202803683370190505b50905060005b848110156113035785858281811061125f5761125f614be2565b905060200201602081019061127491906147ea565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156112ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112de9190614bf8565b8282815181106112f0576112f0614be2565b6020908102919091010152600101611245565b5060008054604051631c2d8fb360e31b81527fe6f126e6caa9e3ecec885b4018b5fc7b4be7215ed294516a21548156199de5b560048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa15801561136d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113919190614142565b6040516360d7faed60e01b81529091506001600160a01b038216906360d7faed906113c8908a908a908a908a908a90600401614e71565b600060405180830381600087803b1580156113e257600080fd5b505af11580156113f6573d6000803e3d6000fd5b505060008054604051631c2d8fb360e31b81527f9973d563e0c2a72196abd7bd620610c30e4e5455956b224d9c2e14b723a3f52060048201529193506001600160a01b0316915063e16c7d9890602401602060405180830381865afa158015611463573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114879190614142565b905060005b868110156115925760008888838181106114a8576114a8614be2565b90506020020160208101906114bd91906147ea565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611503573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115279190614bf8565b90506115898386848151811061153f5761153f614be2565b6020026020010151836115529190614175565b8b8b8681811061156457611564614be2565b905060200201602081019061157991906147ea565b6001600160a01b0316919061377c565b5060010161148c565b505050506115a06001609755565b5050505050565b6115af6134d9565b6115b761351f565b600054604051632474521560e21b81526001600160a01b03909116906391d14854906115f7906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015611614573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116389190614bc5565b6116555760405163d519ed8560e01b815260040160405180910390fd5b6116c56116628380614f6c565b61166b91614fb5565b6116786020850185614f6c565b61168191614fb5565b61168e6040860186614f6c565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506137df92505050565b6117056116d28380614f6c565b6116dc8480614f6c565b6116e96020870187614f6c565b6040880135611700368a90038a0160608b01615028565b61357f565b6111306001609755565b60008054604051631c2d8fb360e31b81527f6bc2c4778697d26fe430a785767cb8ca8f3834a5938a17a9b2fd8a5dab5a19ec6004820152606092839290916001600160a01b039091169063e16c7d9890602401602060405180830381865afa15801561177f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a39190614142565b6040516394f649dd60e01b81523060048201529091506000906001600160a01b038316906394f649dd90602401600060405180830381865afa1580156117ed573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611815919081019061509f565b508051909150611826816001615159565b6001600160401b0381111561183d5761183d614188565b604051908082528060200260200182016040528015611866578160200160208202803683370190505b509450611874816001615159565b6001600160401b0381111561188b5761188b614188565b6040519080825280602002602001820160405280156118b4578160200160208202803683370190505b50935073efefefefefefefefefefefefefefefefefefefef856000815181106118df576118df614be2565b60200260200101906001600160a01b031690816001600160a01b031681525050306001600160a01b03166370ed0ada6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561193d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119619190614bf8565b8460008151811061197457611974614be2565b60200260200101818152505060005b81811015611af75782818151811061199d5761199d614be2565b60200260200101516001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a069190614142565b86611a12836001615159565b81518110611a2257611a22614be2565b60200260200101906001600160a01b031690816001600160a01b031681525050828181518110611a5457611a54614be2565b6020908102919091010151604051630aa794bf60e31b81523060048201526001600160a01b039091169063553ca5f890602401602060405180830381865afa158015611aa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac89190614bf8565b85611ad4836001615159565b81518110611ae457611ae4614be2565b6020908102919091010152600101611983565b505050509091565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490611b3f906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015611b5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b809190614bc5565b611b9d5760405163d519ed8560e01b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81526000805160206158d283398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015611bf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c189190614142565b6040516332afd02f60e01b81529091506001600160a01b038216906332afd02f90611c4d908890889088908890600401615273565b600060405180830381600087803b158015611c6757600080fd5b505af1158015611c7b573d6000803e3d6000fd5b505050505050505050565b60008054604051632474521560e21b81526001600160a01b03909116916391d1485491611cb891903390600401614bae565b602060405180830381865afa158015611cd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf99190614bc5565b611d165760405163bda7a53b60e01b815260040160405180910390fd5b611d1e613a02565b565b611d286134d9565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490611d68906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015611d85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da99190614bc5565b611dc65760405163d519ed8560e01b815260040160405180910390fd5b60005a60c954604051633f65cf1960e01b81529192506001600160a01b031690633f65cf1990611e08908c908c908c908c908c908c908c908c90600401615312565b600060405180830381600087803b158015611e2257600080fd5b505af1158015611e36573d6000803e3d6000fd5b5050505060005b82811015611edd576000611ea5858584818110611e5c57611e5c614be2565b9050602002810190611e6e9190614f6c565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613a5492505050565b9050611ebe633b9aca006001600160401b0383166153b3565b60ca6000828254611ecf9190614175565b909155505050600101611e3d565b50611c7b81613adb565b611eef6134d9565b611ef761351f565b600054604051634df48c7360e11b81526001600160a01b03808416600483015283921690639be918e690602401602060405180830381865afa158015611f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f659190614bc5565b611f825760405163981a2a2b60e01b815260040160405180910390fd5b600054604051632474521560e21b81526001600160a01b03909116906391d1485490611fc2906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015611fdf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120039190614bc5565b6120205760405163d519ed8560e01b815260040160405180910390fd5b600080546040516312fdf3b360e31b81526001600160a01b038581166004830152909116906397ef9d9890602401602060405180830381865afa15801561206b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208f9190614142565b90506001600160a01b0381166120b8576040516306c2b92760e31b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81527f6bc2c4778697d26fe430a785767cb8ca8f3834a5938a17a9b2fd8a5dab5a19ec60048201528592916001600160a01b03169063e16c7d9890602401602060405180830381865afa158015612122573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121469190614142565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038416906370a0823190602401602060405180830381865afa158015612190573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b49190614bf8565b9050836001600160a01b0316866001600160a01b03167f921663a414f798537c348d06b72aad477fa6e6837598798abdcbf700efdbb185836040516121fb91815260200190565b60405180910390a38015612286576040516373d0285560e11b81526001600160a01b03858116600483015284811660248301526044820183905283169063e7a050aa906064016020604051808303816000875af1158015612260573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122849190614bf8565b505b50505050506122956001609755565b50565b6122a061351f565b600054604051632474521560e21b81526001600160a01b03909116906391d14854906122e0906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa1580156122fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123219190614bc5565b61233e5760405163d519ed8560e01b815260040160405180910390fd5b61234783613bdd565b60cb546001600160a01b03161561237157604051631c52d05d60e11b815260040160405180910390fd5b60cb80546001600160a01b0319166001600160a01b038581169190911790915560008054604051631c2d8fb360e31b81527fe6f126e6caa9e3ecec885b4018b5fc7b4be7215ed294516a21548156199de5b560048201529192169063e16c7d9890602401602060405180830381865afa1580156123f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124169190614142565b60cb5460405163eea9064b60e01b81529192506001600160a01b038084169263eea9064b9261244d9216908790879060040161541a565b600060405180830381600087803b15801561246757600080fd5b505af115801561247b573d6000803e3d6000fd5b50506040516001600160a01b03871681527ffe608947467beb30a90e072fd2fc7d52baecf0935f542011fcd8fa6362a5d5b39250602001905060405180910390a15061097b6001609755565b600073efefefefefefefefefefefefefefefefefefefef6001600160a01b0383160361255557306001600160a01b03166370ed0ada6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561252b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061254f9190614bf8565b92915050565b600080546040516312fdf3b360e31b81526001600160a01b038581166004830152909116906397ef9d9890602401602060405180830381865afa1580156125a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c49190614142565b90506001600160a01b0381166125dd5750600092915050565b604051630aa794bf60e31b81523060048201526001600160a01b0382169063553ca5f890602401602060405180830381865afa158015612621573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126459190614bf8565b9392505050565b919050565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490612691906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa1580156126ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126d29190614bc5565b6126ef5760405163d519ed8560e01b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81526000805160206158d283398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612746573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061276a9190614142565b604051632d7688a160e11b81529091506001600160a01b03821690635aed114290611c4d9088908890889088906004016154db565b60008054604051632474521560e21b81526001600160a01b03909116916391d14854916127d191903390600401614bae565b602060405180830381865afa1580156127ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128129190614bc5565b61282f5760405163bda7a53b60e01b815260040160405180910390fd5b61283881613bdd565b600080546001600160a01b0319166001600160a01b038316908117825560405190917f2efdefb1c59d8a7dfe9f3c23f4f98ebc2d088d8ffb45f79d70535c43db1e013a91a250565b600054604051632474521560e21b81526001600160a01b03909116906391d14854906128c0906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa1580156128dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129019190614bc5565b61291e5760405163d519ed8560e01b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81526000805160206158d283398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612975573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129999190614142565b604051631a1b9a0b60e21b81529091506001600160a01b0382169063686e682c906129cc90879087908790600401615511565b600060405180830381600087803b1580156129e657600080fd5b505af11580156111e2573d6000803e3d6000fd5b600054604051634df48c7360e11b81526001600160a01b03808416600483015283921690639be918e690602401602060405180830381865afa158015612a44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a689190614bc5565b612a855760405163981a2a2b60e01b815260040160405180910390fd5b600054604051632474521560e21b81526001600160a01b03909116906391d1485490612ac5906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015612ae2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b069190614bc5565b612b235760405163d519ed8560e01b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81527f6bc2c4778697d26fe430a785767cb8ca8f3834a5938a17a9b2fd8a5dab5a19ec60048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612b8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bb09190614142565b905061097b6001600160a01b03841682600019613c04565b60008054604051631c2d8fb360e31b81527f91904e667b918675a21f3da9d7cac3d4f6722c61ff157d917504d0ff0bcab7ce600482015282916001600160a01b03169063e16c7d9890602401602060405180830381865afa158015612c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c559190614142565b6040516360f4062b60e01b81523060048201529091506000906001600160a01b038316906360f4062b90602401602060405180830381865afa158015612c9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc39190614bf8565b905060008112612ce0578060ca54612cdb9190615159565b612cf6565b612ce981615539565b60ca54612cf69190614175565b9250505090565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490612d3d906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015612d5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d7e9190614bc5565b612d9b5760405163d519ed8560e01b815260040160405180910390fd5b611d1e613d19565b603254610100900460ff1615808015612dc35750603254600160ff909116105b80612ddd5750303b158015612ddd575060325460ff166001145b612e405760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610972565b6032805460ff191660011790558015612e63576032805461ff0019166101001790555b612e6c82613bdd565b612e74613d56565b612e7c613d85565b600080546001600160a01b0319166001600160a01b038416908117825560405190917f2efdefb1c59d8a7dfe9f3c23f4f98ebc2d088d8ffb45f79d70535c43db1e013a91a28015611130576032805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490612f4a906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015612f67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f8b9190614bc5565b612fa85760405163d519ed8560e01b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81526000805160206158d283398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612fff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130239190614142565b6040516336f370b360e21b81526001600160a01b0384811660048301529192509082169063dbcdc2cc906024015b600060405180830381600087803b15801561306b57600080fd5b505af115801561307f573d6000803e3d6000fd5b505050505050565b61308f6134d9565b600054604051632474521560e21b81526001600160a01b03909116906391d14854906130cf906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa1580156130ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131109190614bc5565b61312d5760405163d519ed8560e01b815260040160405180910390fd5b60005a60c954604051637128f7a960e11b81529192506001600160a01b03169063e251ef5290613173908e908e908e908e908e908e908e908e908e908e90600401615555565b600060405180830381600087803b15801561318d57600080fd5b505af11580156131a1573d6000803e3d6000fd5b505050506131ae81613adb565b5050505050505050505050565b6131c36134d9565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490613203906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015613220573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132449190614bc5565b6132615760405163d519ed8560e01b815260040160405180910390fd5b60c95460405163e2c8344560e01b81526001600160a01b038481166004830152602482018490529091169063e2c8344590604401613051565b600054604051632474521560e21b81526001600160a01b03909116906391d14854906132da906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa1580156132f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061331b9190614bc5565b6133385760405163d519ed8560e01b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81526000805160206158d283398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa15801561338f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b39190614142565b60405163bc26e7e560e01b81529091506001600160a01b0382169063bc26e7e5906129cc90309088908890889060040161574f565b6133f06134d9565b6133f861351f565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490613438906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015613455573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134799190614bc5565b6134965760405163d519ed8560e01b815260040160405180910390fd5b6134cf6134a38280614f6c565b6134ac91614fb5565b6134b96020840184614f6c565b6134c291614fb5565b61168e6040850185614f6c565b6122956001609755565b60655460ff1615611d1e5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610972565b6002609754036135715760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610972565b6002609755565b6001609755565b60008054604051631c2d8fb360e31b81527f6743d413553f874d7a6c479fb98f33e5ebd744d8b81a80e0234acca1e3b1ff1560048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa1580156135e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061360c9190614142565b60008054604051631c2d8fb360e31b81526000805160206158d2833981519152600482015292935090916001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015613668573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061368c9190614142565b60405163095ea7b360e01b81526001600160a01b038083166004830152602482018790529192509083169063095ea7b3906044016020604051808303816000875af11580156136df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137039190614bc5565b506040516322f18bf560e01b81526001600160a01b038216906322f18bf59061373e908d908d908d908d908d908d908d908d9060040161578a565b600060405180830381600087803b15801561375857600080fd5b505af115801561376c573d6000803e3d6000fd5b5050505050505050505050505050565b6040516001600160a01b03831660248201526044810182905261097b90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613db4565b805160008190036138035760405163fd152df360e01b815260040160405180910390fd5b606481106138245760405163d966fa9160e01b815260040160405180910390fd5b808451146138455760405163bb3c1a1360e01b815260040160405180910390fd5b80835114613866576040516302023a9760e11b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81527f9cd4436455ecce1ae024fcc129e305bdf14b45a03561d9d9dbe484eec59c2a2f60048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa1580156138cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138f39190614142565b905060006138ff613e89565b905060005b838110156139d057826001600160a01b031663228951186801bc16d674ec80000089848151811061393757613937614be2565b6020026020010151858a868151811061395257613952614be2565b60200260200101518a878151811061396c5761396c614be2565b60200260200101516040518663ffffffff1660e01b815260040161399394939291906157ec565b6000604051808303818588803b1580156139ac57600080fd5b505af11580156139c0573d6000803e3d6000fd5b5050505050806001019050613904565b506139e46801bc16d674ec800000846153b3565b60ca60008282546139f59190615159565b9091555050505050505050565b613a0a613efa565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b600061254f82600281518110613a6c57613a6c614be2565b602002602001015160f881901c60e882901c61ff00161760d882901c62ff0000161760c882901c63ff000000161764ff0000000060b883901c161765ff000000000060a883901c161766ff000000000000609883901c161767ff0000000000000060889290921c919091161790565b60008060009054906101000a90046001600160a01b03166001600160a01b031663bc79a3656040518163ffffffff1660e01b81526004016020604051808303816000875af1158015613b31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b559190614bf8565b905060003a825a613b669086614175565b613b709190615159565b613b7a91906153b3565b33600090815260cc6020526040812080549293508392909190613b9e908490615159565b909155505060405181815233907f4ff29a094e434f8a698185e97d3a285f4ba26c723f8ec8d2c9914213d61589ca9060200160405180910390a2505050565b6001600160a01b038116612295576040516342bcdf7f60e11b815260040160405180910390fd5b801580613c7e5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015613c58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c7c9190614bf8565b155b613ce95760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610972565b6040516001600160a01b03831660248201526044810182905261097b90849063095ea7b360e01b906064016137a8565b613d216134d9565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613a373390565b603254610100900460ff16613d7d5760405162461bcd60e51b815260040161097290615837565b611d1e613f43565b603254610100900460ff16613dac5760405162461bcd60e51b815260040161097290615837565b611d1e613f76565b6000613e09826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613f9d9092919063ffffffff16565b9050805160001480613e2a575080806020019051810190613e2a9190614bc5565b61097b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610972565b60c9546060906001600160a01b0316613eb55760405163104de63b60e21b815260040160405180910390fd5b60c95460408051600160f81b602082015260609290921b6bffffffffffffffffffffffff1916602c8301526000910160408051601f1981840301815291905292915050565b60655460ff16611d1e5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610972565b603254610100900460ff16613f6a5760405162461bcd60e51b815260040161097290615837565b6065805460ff19169055565b603254610100900460ff166135785760405162461bcd60e51b815260040161097290615837565b6060613fac8484600085613fb4565b949350505050565b6060824710156140155760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610972565b600080866001600160a01b031685876040516140319190615882565b60006040518083038185875af1925050503d806000811461406e576040519150601f19603f3d011682016040523d82523d6000602084013e614073565b606091505b50915091506140848783838761408f565b979650505050505050565b606083156140fe5782516000036140f7576001600160a01b0385163b6140f75760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610972565b5081613fac565b613fac83838151156141135781518083602001fd5b8060405162461bcd60e51b8152600401610972919061589e565b6001600160a01b038116811461229557600080fd5b60006020828403121561415457600080fd5b81516126458161412d565b634e487b7160e01b600052601160045260246000fd5b8181038181111561254f5761254f61415f565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156141c6576141c6614188565b604052919050565b60006001600160401b038211156141e7576141e7614188565b5060051b60200190565b803561264c8161412d565b600082601f83011261420d57600080fd5b8135602061422261421d836141ce565b61419e565b82815260059290921b8401810191818101908684111561424157600080fd5b8286015b8481101561425c5780358352918301918301614245565b509695505050505050565b6000806040838503121561427a57600080fd5b82356001600160401b038082111561429157600080fd5b818501915085601f8301126142a557600080fd5b813560206142b561421d836141ce565b82815260059290921b840181019181810190898411156142d457600080fd5b948201945b838610156142fb5785356142ec8161412d565b825294820194908201906142d9565b9650508601359250508082111561431157600080fd5b5061431e858286016141fc565b9150509250929050565b60008083601f84011261433a57600080fd5b5081356001600160401b0381111561435157600080fd5b6020830191508360208260051b850101111561436c57600080fd5b9250929050565b803563ffffffff8116811461264c57600080fd5b80356001600160401b038116811461264c57600080fd5b801515811461229557600080fd5b600060a082840312156143be57600080fd5b60405160a081018181106001600160401b03821117156143e0576143e0614188565b6040529050806143ef83614373565b81526143fd60208401614387565b602082015261440e60408401614387565b604082015260608301356144218161439e565b6060820152608092830135920191909152919050565b600080600080600080600080610120898b03121561445457600080fd5b88356001600160401b038082111561446b57600080fd5b6144778c838d01614328565b909a50985060208b013591508082111561449057600080fd5b61449c8c838d01614328565b909850965060408b01359150808211156144b557600080fd5b506144c28b828c01614328565b909550935050606089013591506144dc8a60808b016143ac565b90509295985092959890939650565b60008060008060006080868803121561450357600080fd5b85356001600160401b038082111561451a57600080fd5b9087019060e0828a03121561452e57600080fd5b9095506020870135908082111561454457600080fd5b5061455188828901614328565b90955093505060408601359150606086013561456c8161439e565b809150509295509295909350565b60006060828403121561458c57600080fd5b50919050565b600080604083850312156145a557600080fd5b82356001600160401b03808211156145bc57600080fd5b6145c88683870161457a565b935060208501359150808211156145de57600080fd5b50830161010081860312156145f257600080fd5b809150509250929050565b600081518084526020808501945080840160005b838110156146365781516001600160a01b031687529582019590820190600101614611565b509495945050505050565b600081518084526020808501945080840160005b8381101561463657815187529582019590820190600101614655565b60408152600061468460408301856145fd565b82810360208401526146968185614641565b95945050505050565b600080600080604085870312156146b557600080fd5b84356001600160401b03808211156146cc57600080fd5b6146d888838901614328565b909650945060208701359150808211156146f157600080fd5b506146fe87828801614328565b95989497509550505050565b60006040828403121561458c57600080fd5b60008060008060008060008060a0898b03121561473857600080fd5b61474189614387565b975060208901356001600160401b038082111561475d57600080fd5b6147698c838d0161470a565b985060408b013591508082111561477f57600080fd5b61478b8c838d01614328565b909850965060608b01359150808211156147a457600080fd5b6147b08c838d01614328565b909650945060808b01359150808211156147c957600080fd5b506147d68b828c01614328565b999c989b5096995094979396929594505050565b6000602082840312156147fc57600080fd5b81356126458161412d565b600082601f83011261481857600080fd5b81356001600160401b0381111561483157614831614188565b614844601f8201601f191660200161419e565b81815284602083860101111561485957600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561488b57600080fd5b83356148968161412d565b925060208401356001600160401b03808211156148b257600080fd5b90850190604082880312156148c657600080fd5b6040516040810181811083821117156148e1576148e1614188565b6040528235828111156148f357600080fd5b6148ff89828601614807565b82525060208301356020820152809450505050604084013590509250925092565b600082601f83011261493157600080fd5b8135602061494161421d836141ce565b82815260059290921b8401810191818101908684111561496057600080fd5b8286015b8481101561425c5761497581614387565b8352918301918301614964565b60008060008060e0858703121561499857600080fd5b84356001600160401b03808211156149af57600080fd5b6149bb88838901614328565b909650945060208701359150808211156149d457600080fd5b506149e187828801614920565b9250506149f186604087016143ac565b905092959194509250565b600080600060e08486031215614a1157600080fd5b83356001600160401b03811115614a2757600080fd5b614a3386828701614920565b93505060208401359150614a4a85604086016143ac565b90509250925092565b60008060008060008060008060008060c08b8d031215614a7257600080fd5b614a7b8b614387565b995060208b01356001600160401b0380821115614a9757600080fd5b614aa38e838f0161470a565b9a5060408d0135915080821115614ab957600080fd5b614ac58e838f01614328565b909a50985060608d0135915080821115614ade57600080fd5b614aea8e838f01614328565b909850965060808d0135915080821115614b0357600080fd5b614b0f8e838f01614328565b909650945060a08d0135915080821115614b2857600080fd5b50614b358d828e01614328565b915080935050809150509295989b9194979a5092959850565b60008060408385031215614b6157600080fd5b8235614b6c8161412d565b946020939093013593505050565b600060208284031215614b8c57600080fd5b81356001600160401b03811115614ba257600080fd5b613fac8482850161457a565b9182526001600160a01b0316602082015260400190565b600060208284031215614bd757600080fd5b81516126458161439e565b634e487b7160e01b600052603260045260246000fd5b600060208284031215614c0a57600080fd5b5051919050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b83811015614c9d57603f19898403018552815160608151818652614c5e828701826145fd565b915050888201518582038a870152614c768282614641565b928901516001600160a01b0316958901959095525094870194925090860190600101614c38565b509098975050505050505050565b60006020808385031215614cbe57600080fd5b82516001600160401b03811115614cd457600080fd5b8301601f81018513614ce557600080fd5b8051614cf361421d826141ce565b81815260059190911b82018301908381019087831115614d1257600080fd5b928401925b8284101561408457835182529284019290840190614d17565b60a0808252865190820181905260009060209060c0840190828a01845b82811015614d6957815184529284019290840190600101614d4d565b50505083810382850152614d7d81896145fd565b9150508281036040840152614d9281876145fd565b90508281036060840152614da68186614641565b9150508260808301529695505050505050565b6000808335601e19843603018112614dd057600080fd5b83016020810192503590506001600160401b03811115614def57600080fd5b8060051b360382131561436c57600080fd5b8183526000602080850194508260005b85811015614636578135614e248161412d565b6001600160a01b031687529582019590820190600101614e11565b81835260006001600160fb1b03831115614e5857600080fd5b8260051b80836020870137939093016020019392505050565b6080815260008635614e828161412d565b6001600160a01b031660808301526020870135614e9e8161412d565b6001600160a01b031660a0830152614eb8604088016141f1565b6001600160a01b031660c0830152606087013560e0830152614edc60808801614373565b63ffffffff16610100830152614ef560a0880188614db9565b60e0610120850152614f0c61016085018284614e01565b915050614f1c60c0890189614db9565b848303607f1901610140860152614f34838284614e3f565b925050508281036020840152614f4b818789614e01565b915050836040830152614f62606083018415159052565b9695505050505050565b6000808335601e19843603018112614f8357600080fd5b8301803591506001600160401b03821115614f9d57600080fd5b6020019150600581901b360382131561436c57600080fd5b6000614fc361421d846141ce565b80848252602080830192508560051b850136811115614fe157600080fd5b855b8181101561501c5780356001600160401b038111156150025760008081fd5b61500e36828a01614807565b865250938201938201614fe3565b50919695505050505050565b600060a0828403121561503a57600080fd5b61264583836143ac565b600082601f83011261505557600080fd5b8151602061506561421d836141ce565b82815260059290921b8401810191818101908684111561508457600080fd5b8286015b8481101561425c5780518352918301918301615088565b600080604083850312156150b257600080fd5b82516001600160401b03808211156150c957600080fd5b818501915085601f8301126150dd57600080fd5b815160206150ed61421d836141ce565b82815260059290921b8401810191818101908984111561510c57600080fd5b948201945b838610156151335785516151248161412d565b82529482019490820190615111565b9188015191965090935050508082111561514c57600080fd5b5061431e85828601615044565b8082018082111561254f5761254f61415f565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e198436030181126151ac57600080fd5b83016020810192503590506001600160401b038111156151cb57600080fd5b80360382131561436c57600080fd5b81835260006020808501808196508560051b810191508460005b8781101561522a57828403895261520b8288615195565b61521686828461516c565b9a87019a95505050908401906001016151f4565b5091979650505050505050565b8183526000602080850194508260005b85811015614636576001600160401b0361526083614387565b1687529582019590820190600101615247565b6040815260006152876040830186886151da565b8281036020840152614084818587615237565b8035825260006152ad6020830183615195565b6040602086015261469660408601828461516c565b81835260006020808501808196508560051b810191508460005b8781101561522a5782840389526152f38288614db9565b6152fe868284614e3f565b9a87019a95505050908401906001016152dc565b6001600160401b03891681526000602060a08184015261533560a084018b61529a565b8381036040850152888152899082016000805b8b81101561537857833564ffffffffff8116808214615365578384fd5b8452509284019291840191600101615348565b5050848103606086015261538d81898b6151da565b9250505082810360808401526153a48185876152c2565b9b9a5050505050505050505050565b808202811582820484141761254f5761254f61415f565b60005b838110156153e55781810151838201526020016153cd565b50506000910152565b600081518084526154068160208601602086016153ca565b601f01601f19169290920160200192915050565b60018060a01b038416815260606020820152600083516040606084015261544460a08401826153ee565b602095909501516080840152505060400152919050565b600081518084526020808501945080840160005b838110156146365781516001600160401b03168752958201959082019060010161546f565b63ffffffff815116825260208101516001600160401b0380821660208501528060408401511660408501525050606081015115156060830152608081015160808301525050565b60e0815260006154ef60e0830186886151da565b8281036020840152615501818661545b565b9150506146966040830184615494565b60e08152600061552460e083018661545b565b9050836020830152613fac6040830184615494565b6000600160ff1b820161554e5761554e61415f565b5060000390565b6001600160401b038b16815260c06020820152600061557760c083018c61529a565b828103604084015289815260208082019060058c901b8301018c60005b8d8110156156fd57848303601f19018452368f900361017e19018235126155ba57600080fd5b8e8235016155c88182615195565b61018086526155dc6101808701828461516c565b9150506155ec6020830183615195565b86830360208801526155ff83828461516c565b925050506156106040830183615195565b868303604088015261562383828461516c565b925050506156346060830183615195565b868303606088015261564783828461516c565b925050506156586080830183615195565b868303608088015261566b83828461516c565b9250505061567b60a08301614387565b6001600160401b031660a086015261569560c08301614387565b6001600160401b031660c08601526156af60e08301614387565b6001600160401b031660e08601526101008281013590860152610120808301359086015261014080830135908601526101609182013591909401526020938401939190910190600101615594565b50508481036060860152615712818b8d6151da565b9250505082810360808401526157298187896152c2565b905082810360a084015261573e8185876152c2565b9d9c50505050505050505050505050565b6001600160a01b0385168152610100602082018190526000906157748382018761545b565b9150508360408301526146966060830184615494565b600061012080835261579f8184018b8d6151da565b905082810360208401526157b481898b615237565b905082810360408401526157c98187896151da565b9150508360608301526157df6080830184615494565b9998505050505050505050565b6080815260006157ff60808301876153ee565b828103602084015261581181876153ee565b9050828103604084015261582581866153ee565b91505082606083015295945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600082516158948184602087016153ca565b9190910192915050565b60208152600061264560208301846153ee56feaf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c12787a29a45ade1f2c8ba759f38026868bdd12692e24087a9ba875581c901d55a2646970667358221220685e5d83008ac48a2cb222a7dfa6879ddcb321c60f20f2e903a500bb7537337564736f6c63430008150033
Deployed Bytecode
0x6080604052600436106101dc5760003560e01c80636794bab211610102578063b915588511610095578063e251ef5211610064578063e251ef52146107bb578063e2c83445146107db578063e4688af8146107fb578063f602e3c51461081b57610436565b8063b915588514610730578063bcbb073a1461075d578063c4d66de81461077b578063dbcdc2cc1461079b57610436565b806370ed0ada116100d157806370ed0ada146106c65780638456cb59146106db57806390fa64a0146106f0578063a3aae1361461071057610436565b80636794bab21461062e578063686e682c1461064e5780636d96a2aa1461066e5780636ffb1ba4146106a657610436565b8063397bfbac1161017a5780635361477b116101495780635361477b146105ab5780635373433f146105cb5780635aed1142146105eb5780635c975abb1461060b57610436565b8063397bfbac146105325780633f4ba83a146105565780633f65cf191461056b5780634798c72b1461058b57610436565b8063286ebd72116101b6578063286ebd72146104b35780632acd560a146104d3578063308dade1146104e657806332afd02f1461051257610436565b80630b10b2011461045c578063176b8b261461047357806322f18bf51461049357610436565b366104365760008054604051631c2d8fb360e31b81527f85629789f35d2cd1a0bb05ebf682211d7611abccda6936d07ccced33f40f293660048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa15801561024a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061026e9190614142565b90506001600160a01b038116330361028257005b60008054604051631c2d8fb360e31b81527fae657eecc2cff849e04b7d2cd73b1b0ec9d31e6e02d73c01e68bf716cf6ae2df600482015282916001600160a01b03169063e16c7d9890602401602060405180830381865afa1580156102eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061030f9190614142565b9050336001600160a01b038216148015610337575032600090815260cc602052604090205415155b1561034f5761034461082e565b915081340361034f57005b60008054604051631c2d8fb360e31b81527f4fa92c822d2e7cfdeb04f7ee17bf84c1e7d1ada8cdd71157b5bab36def2b904360048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa1580156103b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103dc9190614142565b90506103f1816103ec8534614175565b6108c8565b806001600160a01b03167f64459fab7324199920bec86f9ce814dab17621d386f548c8a7c4e638d28fb8f43460405161042c91815260200190565b60405180910390a2005b34801561044257600080fd5b5060405163574b16a760e11b815260040160405180910390fd5b34801561046857600080fd5b50610471610980565b005b34801561047f57600080fd5b5061047161048e366004614267565b610be1565b34801561049f57600080fd5b506104716104ae366004614437565b611134565b3480156104bf57600080fd5b506104716104ce3660046144eb565b6111ec565b6104716104e1366004614592565b6115a7565b3480156104f257600080fd5b506104fb61170f565b604051610509929190614671565b60405180910390f35b34801561051e57600080fd5b5061047161052d36600461469f565b611aff565b34801561053e57600080fd5b5061054860ca5481565b604051908152602001610509565b34801561056257600080fd5b50610471611c86565b34801561057757600080fd5b5061047161058636600461471c565b611d20565b34801561059757600080fd5b506104716105a63660046147ea565b611ee7565b3480156105b757600080fd5b506104716105c6366004614876565b612298565b3480156105d757600080fd5b506105486105e63660046147ea565b6124c7565b3480156105f757600080fd5b50610471610606366004614982565b612651565b34801561061757600080fd5b5060655460ff166040519015158152602001610509565b34801561063a57600080fd5b506104716106493660046147ea565b61279f565b34801561065a57600080fd5b506104716106693660046149fc565b612880565b34801561067a57600080fd5b5060cb5461068e906001600160a01b031681565b6040516001600160a01b039091168152602001610509565b3480156106b257600080fd5b506104716106c13660046147ea565b6129fa565b3480156106d257600080fd5b50610548612bc8565b3480156106e757600080fd5b50610471612cfd565b3480156106fc57600080fd5b5060005461068e906001600160a01b031681565b34801561071c57600080fd5b5060c95461068e906001600160a01b031681565b34801561073c57600080fd5b5061054861074b3660046147ea565b60cc6020526000908152604090205481565b34801561076957600080fd5b5060c9546001600160a01b031661068e565b34801561078757600080fd5b506104716107963660046147ea565b612da3565b3480156107a757600080fd5b506104716107b63660046147ea565b612f0a565b3480156107c757600080fd5b506104716107d6366004614a53565b613087565b3480156107e757600080fd5b506104716107f6366004614b4e565b6131bb565b34801561080757600080fd5b506104716108163660046149fc565b61329a565b610471610829366004614b7a565b6133e8565b32600090815260cc6020526040812054819034101561084d573461085e565b32600090815260cc60205260409020545b905061086a32826108c8565b32600090815260cc602052604081208054839290610889908490614175565b909155505060405181815232907f667ad9c7167aea9bfcff8b321015abb0d8b77cf151a377e09e12b9017f9889fd9060200160405180910390a2919050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114610915576040519150601f19603f3d011682016040523d82523d6000602084013e61091a565b606091505b505090508061097b5760405162461bcd60e51b815260206004820152602260248201527f5472616e7366657248656c7065723a2053656e64696e6720455448206661696c604482015261195960f21b60648201526084015b60405180910390fd5b505050565b60008054604051632474521560e21b81526001600160a01b03909116916391d14854916109b291903390600401614bae565b602060405180830381865afa1580156109cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f39190614bc5565b610a105760405163bda7a53b60e01b815260040160405180910390fd5b60c9546001600160a01b031615610a3a5760405163104de63b60e21b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81527f91904e667b918675a21f3da9d7cac3d4f6722c61ff157d917504d0ff0bcab7ce60048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015610aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac79190614142565b9050806001600160a01b03166384d810626040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610b09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2d9190614142565b5060405163a38406a360e01b81523060048201526001600160a01b0382169063a38406a390602401602060405180830381865afa158015610b72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b969190614142565b60c980546001600160a01b0319166001600160a01b039290921691821790556040517f651d255d6325a0e4d1ff00e7f971fa4ce4cd9d3d43f3be930670471ed88bf85190600090a250565b610be96134d9565b610bf161351f565b60008054604051631c2d8fb360e31b81527f9973d563e0c2a72196abd7bd620610c30e4e5455956b224d9c2e14b723a3f52060048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015610c5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7e9190614142565b9050336001600160a01b03821614610ca9576040516348f5c3ed60e01b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81527fe6f126e6caa9e3ecec885b4018b5fc7b4be7215ed294516a21548156199de5b560048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015610d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d369190614142565b60408051600180825281830190925291925060009190816020015b60408051606080820183528082526020820152600091810191909152815260200190600190039081610d5157905050905084516001600160401b03811115610d9b57610d9b614188565b604051908082528060200260200182016040528015610dc4578160200160208202803683370190505b5081600081518110610dd857610dd8614be2565b60209081029190910101515284516001600160401b03811115610dfd57610dfd614188565b604051908082528060200260200182016040528015610e26578160200160208202803683370190505b5081600081518110610e3a57610e3a614be2565b6020026020010151602001819052503081600081518110610e5d57610e5d614be2565b6020026020010151604001906001600160a01b031690816001600160a01b03168152505060005b855181101561104c576000805487516001600160a01b03909116906397ef9d9890899085908110610eb757610eb7614be2565b60200260200101516040518263ffffffff1660e01b8152600401610eea91906001600160a01b0391909116815260200190565b602060405180830381865afa158015610f07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2b9190614142565b90508083600081518110610f4157610f41614be2565b6020026020010151600001518381518110610f5e57610f5e614be2565b60200260200101906001600160a01b031690816001600160a01b031681525050806001600160a01b0316638c871019878481518110610f9f57610f9f614be2565b60200260200101516040518263ffffffff1660e01b8152600401610fc591815260200190565b6020604051808303816000875af1158015610fe4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110089190614bf8565b8360008151811061101b5761101b614be2565b602002602001015160200151838151811061103857611038614be2565b602090810291909101015250600101610e84565b506040516306ec6e8160e11b81526000906001600160a01b03841690630dd8dd029061107c908590600401614c11565b6000604051808303816000875af115801561109b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526110c39190810190614cab565b90507f203473145f3c567591d6c037fed4bb64bab015c4bf448d0fa16f2e562938e97881836000815181106110fa576110fa614be2565b60200260200101516000015188884360405161111a959493929190614d30565b60405180910390a1505050506111306001609755565b5050565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490611174906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015611191573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b59190614bc5565b6111d25760405163d519ed8560e01b815260040160405180910390fd5b6111e2888888888888888861357f565b5050505050505050565b6111f46134d9565b6111fc61351f565b6000836001600160401b0381111561121657611216614188565b60405190808252806020026020018201604052801561123f578160200160208202803683370190505b50905060005b848110156113035785858281811061125f5761125f614be2565b905060200201602081019061127491906147ea565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156112ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112de9190614bf8565b8282815181106112f0576112f0614be2565b6020908102919091010152600101611245565b5060008054604051631c2d8fb360e31b81527fe6f126e6caa9e3ecec885b4018b5fc7b4be7215ed294516a21548156199de5b560048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa15801561136d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113919190614142565b6040516360d7faed60e01b81529091506001600160a01b038216906360d7faed906113c8908a908a908a908a908a90600401614e71565b600060405180830381600087803b1580156113e257600080fd5b505af11580156113f6573d6000803e3d6000fd5b505060008054604051631c2d8fb360e31b81527f9973d563e0c2a72196abd7bd620610c30e4e5455956b224d9c2e14b723a3f52060048201529193506001600160a01b0316915063e16c7d9890602401602060405180830381865afa158015611463573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114879190614142565b905060005b868110156115925760008888838181106114a8576114a8614be2565b90506020020160208101906114bd91906147ea565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611503573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115279190614bf8565b90506115898386848151811061153f5761153f614be2565b6020026020010151836115529190614175565b8b8b8681811061156457611564614be2565b905060200201602081019061157991906147ea565b6001600160a01b0316919061377c565b5060010161148c565b505050506115a06001609755565b5050505050565b6115af6134d9565b6115b761351f565b600054604051632474521560e21b81526001600160a01b03909116906391d14854906115f7906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015611614573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116389190614bc5565b6116555760405163d519ed8560e01b815260040160405180910390fd5b6116c56116628380614f6c565b61166b91614fb5565b6116786020850185614f6c565b61168191614fb5565b61168e6040860186614f6c565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506137df92505050565b6117056116d28380614f6c565b6116dc8480614f6c565b6116e96020870187614f6c565b6040880135611700368a90038a0160608b01615028565b61357f565b6111306001609755565b60008054604051631c2d8fb360e31b81527f6bc2c4778697d26fe430a785767cb8ca8f3834a5938a17a9b2fd8a5dab5a19ec6004820152606092839290916001600160a01b039091169063e16c7d9890602401602060405180830381865afa15801561177f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a39190614142565b6040516394f649dd60e01b81523060048201529091506000906001600160a01b038316906394f649dd90602401600060405180830381865afa1580156117ed573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611815919081019061509f565b508051909150611826816001615159565b6001600160401b0381111561183d5761183d614188565b604051908082528060200260200182016040528015611866578160200160208202803683370190505b509450611874816001615159565b6001600160401b0381111561188b5761188b614188565b6040519080825280602002602001820160405280156118b4578160200160208202803683370190505b50935073efefefefefefefefefefefefefefefefefefefef856000815181106118df576118df614be2565b60200260200101906001600160a01b031690816001600160a01b031681525050306001600160a01b03166370ed0ada6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561193d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119619190614bf8565b8460008151811061197457611974614be2565b60200260200101818152505060005b81811015611af75782818151811061199d5761199d614be2565b60200260200101516001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a069190614142565b86611a12836001615159565b81518110611a2257611a22614be2565b60200260200101906001600160a01b031690816001600160a01b031681525050828181518110611a5457611a54614be2565b6020908102919091010151604051630aa794bf60e31b81523060048201526001600160a01b039091169063553ca5f890602401602060405180830381865afa158015611aa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac89190614bf8565b85611ad4836001615159565b81518110611ae457611ae4614be2565b6020908102919091010152600101611983565b505050509091565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490611b3f906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015611b5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b809190614bc5565b611b9d5760405163d519ed8560e01b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81526000805160206158d283398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015611bf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c189190614142565b6040516332afd02f60e01b81529091506001600160a01b038216906332afd02f90611c4d908890889088908890600401615273565b600060405180830381600087803b158015611c6757600080fd5b505af1158015611c7b573d6000803e3d6000fd5b505050505050505050565b60008054604051632474521560e21b81526001600160a01b03909116916391d1485491611cb891903390600401614bae565b602060405180830381865afa158015611cd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf99190614bc5565b611d165760405163bda7a53b60e01b815260040160405180910390fd5b611d1e613a02565b565b611d286134d9565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490611d68906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015611d85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da99190614bc5565b611dc65760405163d519ed8560e01b815260040160405180910390fd5b60005a60c954604051633f65cf1960e01b81529192506001600160a01b031690633f65cf1990611e08908c908c908c908c908c908c908c908c90600401615312565b600060405180830381600087803b158015611e2257600080fd5b505af1158015611e36573d6000803e3d6000fd5b5050505060005b82811015611edd576000611ea5858584818110611e5c57611e5c614be2565b9050602002810190611e6e9190614f6c565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613a5492505050565b9050611ebe633b9aca006001600160401b0383166153b3565b60ca6000828254611ecf9190614175565b909155505050600101611e3d565b50611c7b81613adb565b611eef6134d9565b611ef761351f565b600054604051634df48c7360e11b81526001600160a01b03808416600483015283921690639be918e690602401602060405180830381865afa158015611f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f659190614bc5565b611f825760405163981a2a2b60e01b815260040160405180910390fd5b600054604051632474521560e21b81526001600160a01b03909116906391d1485490611fc2906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015611fdf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120039190614bc5565b6120205760405163d519ed8560e01b815260040160405180910390fd5b600080546040516312fdf3b360e31b81526001600160a01b038581166004830152909116906397ef9d9890602401602060405180830381865afa15801561206b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208f9190614142565b90506001600160a01b0381166120b8576040516306c2b92760e31b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81527f6bc2c4778697d26fe430a785767cb8ca8f3834a5938a17a9b2fd8a5dab5a19ec60048201528592916001600160a01b03169063e16c7d9890602401602060405180830381865afa158015612122573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121469190614142565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038416906370a0823190602401602060405180830381865afa158015612190573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b49190614bf8565b9050836001600160a01b0316866001600160a01b03167f921663a414f798537c348d06b72aad477fa6e6837598798abdcbf700efdbb185836040516121fb91815260200190565b60405180910390a38015612286576040516373d0285560e11b81526001600160a01b03858116600483015284811660248301526044820183905283169063e7a050aa906064016020604051808303816000875af1158015612260573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122849190614bf8565b505b50505050506122956001609755565b50565b6122a061351f565b600054604051632474521560e21b81526001600160a01b03909116906391d14854906122e0906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa1580156122fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123219190614bc5565b61233e5760405163d519ed8560e01b815260040160405180910390fd5b61234783613bdd565b60cb546001600160a01b03161561237157604051631c52d05d60e11b815260040160405180910390fd5b60cb80546001600160a01b0319166001600160a01b038581169190911790915560008054604051631c2d8fb360e31b81527fe6f126e6caa9e3ecec885b4018b5fc7b4be7215ed294516a21548156199de5b560048201529192169063e16c7d9890602401602060405180830381865afa1580156123f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124169190614142565b60cb5460405163eea9064b60e01b81529192506001600160a01b038084169263eea9064b9261244d9216908790879060040161541a565b600060405180830381600087803b15801561246757600080fd5b505af115801561247b573d6000803e3d6000fd5b50506040516001600160a01b03871681527ffe608947467beb30a90e072fd2fc7d52baecf0935f542011fcd8fa6362a5d5b39250602001905060405180910390a15061097b6001609755565b600073efefefefefefefefefefefefefefefefefefefef6001600160a01b0383160361255557306001600160a01b03166370ed0ada6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561252b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061254f9190614bf8565b92915050565b600080546040516312fdf3b360e31b81526001600160a01b038581166004830152909116906397ef9d9890602401602060405180830381865afa1580156125a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c49190614142565b90506001600160a01b0381166125dd5750600092915050565b604051630aa794bf60e31b81523060048201526001600160a01b0382169063553ca5f890602401602060405180830381865afa158015612621573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126459190614bf8565b9392505050565b919050565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490612691906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa1580156126ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126d29190614bc5565b6126ef5760405163d519ed8560e01b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81526000805160206158d283398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612746573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061276a9190614142565b604051632d7688a160e11b81529091506001600160a01b03821690635aed114290611c4d9088908890889088906004016154db565b60008054604051632474521560e21b81526001600160a01b03909116916391d14854916127d191903390600401614bae565b602060405180830381865afa1580156127ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128129190614bc5565b61282f5760405163bda7a53b60e01b815260040160405180910390fd5b61283881613bdd565b600080546001600160a01b0319166001600160a01b038316908117825560405190917f2efdefb1c59d8a7dfe9f3c23f4f98ebc2d088d8ffb45f79d70535c43db1e013a91a250565b600054604051632474521560e21b81526001600160a01b03909116906391d14854906128c0906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa1580156128dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129019190614bc5565b61291e5760405163d519ed8560e01b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81526000805160206158d283398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612975573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129999190614142565b604051631a1b9a0b60e21b81529091506001600160a01b0382169063686e682c906129cc90879087908790600401615511565b600060405180830381600087803b1580156129e657600080fd5b505af11580156111e2573d6000803e3d6000fd5b600054604051634df48c7360e11b81526001600160a01b03808416600483015283921690639be918e690602401602060405180830381865afa158015612a44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a689190614bc5565b612a855760405163981a2a2b60e01b815260040160405180910390fd5b600054604051632474521560e21b81526001600160a01b03909116906391d1485490612ac5906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015612ae2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b069190614bc5565b612b235760405163d519ed8560e01b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81527f6bc2c4778697d26fe430a785767cb8ca8f3834a5938a17a9b2fd8a5dab5a19ec60048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612b8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bb09190614142565b905061097b6001600160a01b03841682600019613c04565b60008054604051631c2d8fb360e31b81527f91904e667b918675a21f3da9d7cac3d4f6722c61ff157d917504d0ff0bcab7ce600482015282916001600160a01b03169063e16c7d9890602401602060405180830381865afa158015612c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c559190614142565b6040516360f4062b60e01b81523060048201529091506000906001600160a01b038316906360f4062b90602401602060405180830381865afa158015612c9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc39190614bf8565b905060008112612ce0578060ca54612cdb9190615159565b612cf6565b612ce981615539565b60ca54612cf69190614175565b9250505090565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490612d3d906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015612d5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d7e9190614bc5565b612d9b5760405163d519ed8560e01b815260040160405180910390fd5b611d1e613d19565b603254610100900460ff1615808015612dc35750603254600160ff909116105b80612ddd5750303b158015612ddd575060325460ff166001145b612e405760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610972565b6032805460ff191660011790558015612e63576032805461ff0019166101001790555b612e6c82613bdd565b612e74613d56565b612e7c613d85565b600080546001600160a01b0319166001600160a01b038416908117825560405190917f2efdefb1c59d8a7dfe9f3c23f4f98ebc2d088d8ffb45f79d70535c43db1e013a91a28015611130576032805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490612f4a906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015612f67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f8b9190614bc5565b612fa85760405163d519ed8560e01b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81526000805160206158d283398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612fff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130239190614142565b6040516336f370b360e21b81526001600160a01b0384811660048301529192509082169063dbcdc2cc906024015b600060405180830381600087803b15801561306b57600080fd5b505af115801561307f573d6000803e3d6000fd5b505050505050565b61308f6134d9565b600054604051632474521560e21b81526001600160a01b03909116906391d14854906130cf906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa1580156130ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131109190614bc5565b61312d5760405163d519ed8560e01b815260040160405180910390fd5b60005a60c954604051637128f7a960e11b81529192506001600160a01b03169063e251ef5290613173908e908e908e908e908e908e908e908e908e908e90600401615555565b600060405180830381600087803b15801561318d57600080fd5b505af11580156131a1573d6000803e3d6000fd5b505050506131ae81613adb565b5050505050505050505050565b6131c36134d9565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490613203906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015613220573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132449190614bc5565b6132615760405163d519ed8560e01b815260040160405180910390fd5b60c95460405163e2c8344560e01b81526001600160a01b038481166004830152602482018490529091169063e2c8344590604401613051565b600054604051632474521560e21b81526001600160a01b03909116906391d14854906132da906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa1580156132f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061331b9190614bc5565b6133385760405163d519ed8560e01b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81526000805160206158d283398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa15801561338f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b39190614142565b60405163bc26e7e560e01b81529091506001600160a01b0382169063bc26e7e5906129cc90309088908890889060040161574f565b6133f06134d9565b6133f861351f565b600054604051632474521560e21b81526001600160a01b03909116906391d1485490613438906000805160206158b2833981519152903390600401614bae565b602060405180830381865afa158015613455573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134799190614bc5565b6134965760405163d519ed8560e01b815260040160405180910390fd5b6134cf6134a38280614f6c565b6134ac91614fb5565b6134b96020840184614f6c565b6134c291614fb5565b61168e6040850185614f6c565b6122956001609755565b60655460ff1615611d1e5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610972565b6002609754036135715760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610972565b6002609755565b6001609755565b60008054604051631c2d8fb360e31b81527f6743d413553f874d7a6c479fb98f33e5ebd744d8b81a80e0234acca1e3b1ff1560048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa1580156135e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061360c9190614142565b60008054604051631c2d8fb360e31b81526000805160206158d2833981519152600482015292935090916001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015613668573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061368c9190614142565b60405163095ea7b360e01b81526001600160a01b038083166004830152602482018790529192509083169063095ea7b3906044016020604051808303816000875af11580156136df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137039190614bc5565b506040516322f18bf560e01b81526001600160a01b038216906322f18bf59061373e908d908d908d908d908d908d908d908d9060040161578a565b600060405180830381600087803b15801561375857600080fd5b505af115801561376c573d6000803e3d6000fd5b5050505050505050505050505050565b6040516001600160a01b03831660248201526044810182905261097b90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613db4565b805160008190036138035760405163fd152df360e01b815260040160405180910390fd5b606481106138245760405163d966fa9160e01b815260040160405180910390fd5b808451146138455760405163bb3c1a1360e01b815260040160405180910390fd5b80835114613866576040516302023a9760e11b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81527f9cd4436455ecce1ae024fcc129e305bdf14b45a03561d9d9dbe484eec59c2a2f60048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa1580156138cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138f39190614142565b905060006138ff613e89565b905060005b838110156139d057826001600160a01b031663228951186801bc16d674ec80000089848151811061393757613937614be2565b6020026020010151858a868151811061395257613952614be2565b60200260200101518a878151811061396c5761396c614be2565b60200260200101516040518663ffffffff1660e01b815260040161399394939291906157ec565b6000604051808303818588803b1580156139ac57600080fd5b505af11580156139c0573d6000803e3d6000fd5b5050505050806001019050613904565b506139e46801bc16d674ec800000846153b3565b60ca60008282546139f59190615159565b9091555050505050505050565b613a0a613efa565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b600061254f82600281518110613a6c57613a6c614be2565b602002602001015160f881901c60e882901c61ff00161760d882901c62ff0000161760c882901c63ff000000161764ff0000000060b883901c161765ff000000000060a883901c161766ff000000000000609883901c161767ff0000000000000060889290921c919091161790565b60008060009054906101000a90046001600160a01b03166001600160a01b031663bc79a3656040518163ffffffff1660e01b81526004016020604051808303816000875af1158015613b31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b559190614bf8565b905060003a825a613b669086614175565b613b709190615159565b613b7a91906153b3565b33600090815260cc6020526040812080549293508392909190613b9e908490615159565b909155505060405181815233907f4ff29a094e434f8a698185e97d3a285f4ba26c723f8ec8d2c9914213d61589ca9060200160405180910390a2505050565b6001600160a01b038116612295576040516342bcdf7f60e11b815260040160405180910390fd5b801580613c7e5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015613c58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c7c9190614bf8565b155b613ce95760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610972565b6040516001600160a01b03831660248201526044810182905261097b90849063095ea7b360e01b906064016137a8565b613d216134d9565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613a373390565b603254610100900460ff16613d7d5760405162461bcd60e51b815260040161097290615837565b611d1e613f43565b603254610100900460ff16613dac5760405162461bcd60e51b815260040161097290615837565b611d1e613f76565b6000613e09826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613f9d9092919063ffffffff16565b9050805160001480613e2a575080806020019051810190613e2a9190614bc5565b61097b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610972565b60c9546060906001600160a01b0316613eb55760405163104de63b60e21b815260040160405180910390fd5b60c95460408051600160f81b602082015260609290921b6bffffffffffffffffffffffff1916602c8301526000910160408051601f1981840301815291905292915050565b60655460ff16611d1e5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610972565b603254610100900460ff16613f6a5760405162461bcd60e51b815260040161097290615837565b6065805460ff19169055565b603254610100900460ff166135785760405162461bcd60e51b815260040161097290615837565b6060613fac8484600085613fb4565b949350505050565b6060824710156140155760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610972565b600080866001600160a01b031685876040516140319190615882565b60006040518083038185875af1925050503d806000811461406e576040519150601f19603f3d011682016040523d82523d6000602084013e614073565b606091505b50915091506140848783838761408f565b979650505050505050565b606083156140fe5782516000036140f7576001600160a01b0385163b6140f75760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610972565b5081613fac565b613fac83838151156141135781518083602001fd5b8060405162461bcd60e51b8152600401610972919061589e565b6001600160a01b038116811461229557600080fd5b60006020828403121561415457600080fd5b81516126458161412d565b634e487b7160e01b600052601160045260246000fd5b8181038181111561254f5761254f61415f565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156141c6576141c6614188565b604052919050565b60006001600160401b038211156141e7576141e7614188565b5060051b60200190565b803561264c8161412d565b600082601f83011261420d57600080fd5b8135602061422261421d836141ce565b61419e565b82815260059290921b8401810191818101908684111561424157600080fd5b8286015b8481101561425c5780358352918301918301614245565b509695505050505050565b6000806040838503121561427a57600080fd5b82356001600160401b038082111561429157600080fd5b818501915085601f8301126142a557600080fd5b813560206142b561421d836141ce565b82815260059290921b840181019181810190898411156142d457600080fd5b948201945b838610156142fb5785356142ec8161412d565b825294820194908201906142d9565b9650508601359250508082111561431157600080fd5b5061431e858286016141fc565b9150509250929050565b60008083601f84011261433a57600080fd5b5081356001600160401b0381111561435157600080fd5b6020830191508360208260051b850101111561436c57600080fd5b9250929050565b803563ffffffff8116811461264c57600080fd5b80356001600160401b038116811461264c57600080fd5b801515811461229557600080fd5b600060a082840312156143be57600080fd5b60405160a081018181106001600160401b03821117156143e0576143e0614188565b6040529050806143ef83614373565b81526143fd60208401614387565b602082015261440e60408401614387565b604082015260608301356144218161439e565b6060820152608092830135920191909152919050565b600080600080600080600080610120898b03121561445457600080fd5b88356001600160401b038082111561446b57600080fd5b6144778c838d01614328565b909a50985060208b013591508082111561449057600080fd5b61449c8c838d01614328565b909850965060408b01359150808211156144b557600080fd5b506144c28b828c01614328565b909550935050606089013591506144dc8a60808b016143ac565b90509295985092959890939650565b60008060008060006080868803121561450357600080fd5b85356001600160401b038082111561451a57600080fd5b9087019060e0828a03121561452e57600080fd5b9095506020870135908082111561454457600080fd5b5061455188828901614328565b90955093505060408601359150606086013561456c8161439e565b809150509295509295909350565b60006060828403121561458c57600080fd5b50919050565b600080604083850312156145a557600080fd5b82356001600160401b03808211156145bc57600080fd5b6145c88683870161457a565b935060208501359150808211156145de57600080fd5b50830161010081860312156145f257600080fd5b809150509250929050565b600081518084526020808501945080840160005b838110156146365781516001600160a01b031687529582019590820190600101614611565b509495945050505050565b600081518084526020808501945080840160005b8381101561463657815187529582019590820190600101614655565b60408152600061468460408301856145fd565b82810360208401526146968185614641565b95945050505050565b600080600080604085870312156146b557600080fd5b84356001600160401b03808211156146cc57600080fd5b6146d888838901614328565b909650945060208701359150808211156146f157600080fd5b506146fe87828801614328565b95989497509550505050565b60006040828403121561458c57600080fd5b60008060008060008060008060a0898b03121561473857600080fd5b61474189614387565b975060208901356001600160401b038082111561475d57600080fd5b6147698c838d0161470a565b985060408b013591508082111561477f57600080fd5b61478b8c838d01614328565b909850965060608b01359150808211156147a457600080fd5b6147b08c838d01614328565b909650945060808b01359150808211156147c957600080fd5b506147d68b828c01614328565b999c989b5096995094979396929594505050565b6000602082840312156147fc57600080fd5b81356126458161412d565b600082601f83011261481857600080fd5b81356001600160401b0381111561483157614831614188565b614844601f8201601f191660200161419e565b81815284602083860101111561485957600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561488b57600080fd5b83356148968161412d565b925060208401356001600160401b03808211156148b257600080fd5b90850190604082880312156148c657600080fd5b6040516040810181811083821117156148e1576148e1614188565b6040528235828111156148f357600080fd5b6148ff89828601614807565b82525060208301356020820152809450505050604084013590509250925092565b600082601f83011261493157600080fd5b8135602061494161421d836141ce565b82815260059290921b8401810191818101908684111561496057600080fd5b8286015b8481101561425c5761497581614387565b8352918301918301614964565b60008060008060e0858703121561499857600080fd5b84356001600160401b03808211156149af57600080fd5b6149bb88838901614328565b909650945060208701359150808211156149d457600080fd5b506149e187828801614920565b9250506149f186604087016143ac565b905092959194509250565b600080600060e08486031215614a1157600080fd5b83356001600160401b03811115614a2757600080fd5b614a3386828701614920565b93505060208401359150614a4a85604086016143ac565b90509250925092565b60008060008060008060008060008060c08b8d031215614a7257600080fd5b614a7b8b614387565b995060208b01356001600160401b0380821115614a9757600080fd5b614aa38e838f0161470a565b9a5060408d0135915080821115614ab957600080fd5b614ac58e838f01614328565b909a50985060608d0135915080821115614ade57600080fd5b614aea8e838f01614328565b909850965060808d0135915080821115614b0357600080fd5b614b0f8e838f01614328565b909650945060a08d0135915080821115614b2857600080fd5b50614b358d828e01614328565b915080935050809150509295989b9194979a5092959850565b60008060408385031215614b6157600080fd5b8235614b6c8161412d565b946020939093013593505050565b600060208284031215614b8c57600080fd5b81356001600160401b03811115614ba257600080fd5b613fac8482850161457a565b9182526001600160a01b0316602082015260400190565b600060208284031215614bd757600080fd5b81516126458161439e565b634e487b7160e01b600052603260045260246000fd5b600060208284031215614c0a57600080fd5b5051919050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b83811015614c9d57603f19898403018552815160608151818652614c5e828701826145fd565b915050888201518582038a870152614c768282614641565b928901516001600160a01b0316958901959095525094870194925090860190600101614c38565b509098975050505050505050565b60006020808385031215614cbe57600080fd5b82516001600160401b03811115614cd457600080fd5b8301601f81018513614ce557600080fd5b8051614cf361421d826141ce565b81815260059190911b82018301908381019087831115614d1257600080fd5b928401925b8284101561408457835182529284019290840190614d17565b60a0808252865190820181905260009060209060c0840190828a01845b82811015614d6957815184529284019290840190600101614d4d565b50505083810382850152614d7d81896145fd565b9150508281036040840152614d9281876145fd565b90508281036060840152614da68186614641565b9150508260808301529695505050505050565b6000808335601e19843603018112614dd057600080fd5b83016020810192503590506001600160401b03811115614def57600080fd5b8060051b360382131561436c57600080fd5b8183526000602080850194508260005b85811015614636578135614e248161412d565b6001600160a01b031687529582019590820190600101614e11565b81835260006001600160fb1b03831115614e5857600080fd5b8260051b80836020870137939093016020019392505050565b6080815260008635614e828161412d565b6001600160a01b031660808301526020870135614e9e8161412d565b6001600160a01b031660a0830152614eb8604088016141f1565b6001600160a01b031660c0830152606087013560e0830152614edc60808801614373565b63ffffffff16610100830152614ef560a0880188614db9565b60e0610120850152614f0c61016085018284614e01565b915050614f1c60c0890189614db9565b848303607f1901610140860152614f34838284614e3f565b925050508281036020840152614f4b818789614e01565b915050836040830152614f62606083018415159052565b9695505050505050565b6000808335601e19843603018112614f8357600080fd5b8301803591506001600160401b03821115614f9d57600080fd5b6020019150600581901b360382131561436c57600080fd5b6000614fc361421d846141ce565b80848252602080830192508560051b850136811115614fe157600080fd5b855b8181101561501c5780356001600160401b038111156150025760008081fd5b61500e36828a01614807565b865250938201938201614fe3565b50919695505050505050565b600060a0828403121561503a57600080fd5b61264583836143ac565b600082601f83011261505557600080fd5b8151602061506561421d836141ce565b82815260059290921b8401810191818101908684111561508457600080fd5b8286015b8481101561425c5780518352918301918301615088565b600080604083850312156150b257600080fd5b82516001600160401b03808211156150c957600080fd5b818501915085601f8301126150dd57600080fd5b815160206150ed61421d836141ce565b82815260059290921b8401810191818101908984111561510c57600080fd5b948201945b838610156151335785516151248161412d565b82529482019490820190615111565b9188015191965090935050508082111561514c57600080fd5b5061431e85828601615044565b8082018082111561254f5761254f61415f565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e198436030181126151ac57600080fd5b83016020810192503590506001600160401b038111156151cb57600080fd5b80360382131561436c57600080fd5b81835260006020808501808196508560051b810191508460005b8781101561522a57828403895261520b8288615195565b61521686828461516c565b9a87019a95505050908401906001016151f4565b5091979650505050505050565b8183526000602080850194508260005b85811015614636576001600160401b0361526083614387565b1687529582019590820190600101615247565b6040815260006152876040830186886151da565b8281036020840152614084818587615237565b8035825260006152ad6020830183615195565b6040602086015261469660408601828461516c565b81835260006020808501808196508560051b810191508460005b8781101561522a5782840389526152f38288614db9565b6152fe868284614e3f565b9a87019a95505050908401906001016152dc565b6001600160401b03891681526000602060a08184015261533560a084018b61529a565b8381036040850152888152899082016000805b8b81101561537857833564ffffffffff8116808214615365578384fd5b8452509284019291840191600101615348565b5050848103606086015261538d81898b6151da565b9250505082810360808401526153a48185876152c2565b9b9a5050505050505050505050565b808202811582820484141761254f5761254f61415f565b60005b838110156153e55781810151838201526020016153cd565b50506000910152565b600081518084526154068160208601602086016153ca565b601f01601f19169290920160200192915050565b60018060a01b038416815260606020820152600083516040606084015261544460a08401826153ee565b602095909501516080840152505060400152919050565b600081518084526020808501945080840160005b838110156146365781516001600160401b03168752958201959082019060010161546f565b63ffffffff815116825260208101516001600160401b0380821660208501528060408401511660408501525050606081015115156060830152608081015160808301525050565b60e0815260006154ef60e0830186886151da565b8281036020840152615501818661545b565b9150506146966040830184615494565b60e08152600061552460e083018661545b565b9050836020830152613fac6040830184615494565b6000600160ff1b820161554e5761554e61415f565b5060000390565b6001600160401b038b16815260c06020820152600061557760c083018c61529a565b828103604084015289815260208082019060058c901b8301018c60005b8d8110156156fd57848303601f19018452368f900361017e19018235126155ba57600080fd5b8e8235016155c88182615195565b61018086526155dc6101808701828461516c565b9150506155ec6020830183615195565b86830360208801526155ff83828461516c565b925050506156106040830183615195565b868303604088015261562383828461516c565b925050506156346060830183615195565b868303606088015261564783828461516c565b925050506156586080830183615195565b868303608088015261566b83828461516c565b9250505061567b60a08301614387565b6001600160401b031660a086015261569560c08301614387565b6001600160401b031660c08601526156af60e08301614387565b6001600160401b031660e08601526101008281013590860152610120808301359086015261014080830135908601526101609182013591909401526020938401939190910190600101615594565b50508481036060860152615712818b8d6151da565b9250505082810360808401526157298187896152c2565b905082810360a084015261573e8185876152c2565b9d9c50505050505050505050505050565b6001600160a01b0385168152610100602082018190526000906157748382018761545b565b9150508360408301526146966060830184615494565b600061012080835261579f8184018b8d6151da565b905082810360208401526157b481898b615237565b905082810360408401526157c98187896151da565b9150508360608301526157df6080830184615494565b9998505050505050505050565b6080815260006157ff60808301876153ee565b828103602084015261581181876153ee565b9050828103604084015261582581866153ee565b91505082606083015295945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600082516158948184602087016153ca565b9190910192915050565b60208152600061264560208301846153ee56feaf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c12787a29a45ade1f2c8ba759f38026868bdd12692e24087a9ba875581c901d55a2646970667358221220685e5d83008ac48a2cb222a7dfa6879ddcb321c60f20f2e903a500bb7537337564736f6c63430008150033
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.