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 | 20039666 | 155 days ago | IN | 0 ETH | 0.04951916 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
LRTDepositPool
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 10000 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import { UtilLib } from "./utils/UtilLib.sol"; import { LRTConstants } from "./utils/LRTConstants.sol"; import { LRTConfigRoleChecker, ILRTConfig } from "./utils/LRTConfigRoleChecker.sol"; import { IRSETH } from "./interfaces/IRSETH.sol"; import { ILRTOracle } from "./interfaces/ILRTOracle.sol"; import { INodeDelegator } from "./interfaces/INodeDelegator.sol"; import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol"; import { ILRTUnstakingVault } from "./interfaces/ILRTUnstakingVault.sol"; import { ILRTWithdrawalManager } from "./interfaces/ILRTWithdrawalManager.sol"; import { ILRTConverter } from "./interfaces/ILRTConverter.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; /// @title LRTDepositPool - Deposit Pool Contract for LSTs /// @notice Handles LST asset deposits contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable { using SafeERC20 for IERC20; uint256 public maxNodeDelegatorLimit; uint256 public minAmountToDeposit; mapping(address => uint256) public isNodeDelegator; // 0: not a node delegator, 1: is a node delegator address[] public nodeDelegatorQueue; /// @notice maximum amount that can be ignored uint256 public maxNegligibleAmount; /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /// @dev Initializes the contract /// @param lrtConfigAddr LRT config address function initialize(address lrtConfigAddr) external initializer { UtilLib.checkNonZeroAddress(lrtConfigAddr); __Pausable_init(); __ReentrancyGuard_init(); maxNodeDelegatorLimit = 10; lrtConfig = ILRTConfig(lrtConfigAddr); emit UpdatedLRTConfig(lrtConfigAddr); } /*////////////////////////////////////////////////////////////// receive functions //////////////////////////////////////////////////////////////*/ receive() external payable { } /// @dev receive from RewardReceiver function receiveFromRewardReceiver() external payable { } /// @dev receive from LRTConverter function receiveFromLRTConverter() external payable { } /// @dev receive from NodeDelegator function receiveFromNodeDelegator() external payable { } /*////////////////////////////////////////////////////////////// user interactions //////////////////////////////////////////////////////////////*/ /// @notice Allows user to deposit ETH to the protocol /// @param minRSETHAmountExpected Minimum amount of rseth to receive /// @param referralId referral id function depositETH( uint256 minRSETHAmountExpected, string calldata referralId ) external payable nonReentrant whenNotPaused { // checks uint256 rsethAmountToMint = _beforeDeposit(LRTConstants.ETH_TOKEN, msg.value, minRSETHAmountExpected); // interactions _mintRsETH(rsethAmountToMint); emit ETHDeposit(msg.sender, msg.value, rsethAmountToMint, referralId); } /// @notice helps user stake LST to the protocol /// @param asset LST asset address to stake /// @param depositAmount LST asset amount to stake /// @param minRSETHAmountExpected Minimum amount of rseth to receive function depositAsset( address asset, uint256 depositAmount, uint256 minRSETHAmountExpected, string calldata referralId ) external nonReentrant whenNotPaused onlySupportedAsset(asset) { // checks uint256 rsethAmountToMint = _beforeDeposit(asset, depositAmount, minRSETHAmountExpected); // interactions IERC20(asset).safeTransferFrom(msg.sender, address(this), depositAmount); _mintRsETH(rsethAmountToMint); emit AssetDeposit(msg.sender, asset, depositAmount, rsethAmountToMint, referralId); } /*////////////////////////////////////////////////////////////// Fund movement functions //////////////////////////////////////////////////////////////*/ /// @notice swap ETH for LST asset which is accepted by LRTDepositPool /// @dev use LRTOracle to get price for toToken. Only callable by LRT manager /// @param toAsset Asset address to swap to /// @param minToAssetAmount Minimum asset amount to swap to function swapETHForAssetWithinDepositPool( address toAsset, uint256 minToAssetAmount ) external payable onlyLRTManager onlySupportedAsset(toAsset) { // checks uint256 ethAmountSent = msg.value; uint256 returnAmount = getSwapETHToAssetReturnAmount(toAsset, ethAmountSent); if (returnAmount < minToAssetAmount || IERC20(toAsset).balanceOf(address(this)) < returnAmount) { revert NotEnoughAssetToTransfer(); } // interactions IERC20(toAsset).transfer(msg.sender, returnAmount); emit ETHSwappedForLST(ethAmountSent, toAsset, returnAmount); } /// @notice transfers asset lying in this DepositPool to node delegator contract /// @dev only callable by LRT manager /// @param ndcIndex Index of NodeDelegator contract address in nodeDelegatorQueue /// @param asset Asset address /// @param amount Asset amount to transfer function transferAssetToNodeDelegator( uint256 ndcIndex, address asset, uint256 amount ) external nonReentrant onlyLRTManager onlySupportedAsset(asset) { address nodeDelegator = nodeDelegatorQueue[ndcIndex]; IERC20(asset).safeTransfer(nodeDelegator, amount); } /// @notice transfers ETH lying in this DepositPool to node delegator contract /// @dev only callable by LRT manager /// @param ndcIndex Index of NodeDelegator contract address in nodeDelegatorQueue /// @param amount ETH amount to transfer function transferETHToNodeDelegator(uint256 ndcIndex, uint256 amount) external nonReentrant onlyLRTManager { address nodeDelegator = nodeDelegatorQueue[ndcIndex]; INodeDelegator(nodeDelegator).sendETHFromDepositPoolToNDC{ value: amount }(); emit EthTransferred(nodeDelegator, amount); } /// @notice transfers asset lying in this DepositPool to LRTUnstakingVault contract /// @dev only callable by LRT manager /// @param asset Asset address /// @param amount Asset amount to transfer function transferAssetToLRTUnstakingVault( address asset, uint256 amount ) external nonReentrant onlyLRTManager onlySupportedAsset(asset) { address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); IERC20(asset).safeTransfer(lrtUnstakingVault, amount); } /// @notice transfers ETH lying in this DepositPool to nLRTUnstakingVault contract /// @dev only callable by LRT manager /// @param amount ETH amount to transfer function transferETHToLRTUnstakingVault(uint256 amount) external nonReentrant onlyLRTManager { address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); ILRTUnstakingVault(lrtUnstakingVault).receiveFromLRTDepositPool{ value: amount }(); emit EthTransferred(lrtUnstakingVault, amount); } /*////////////////////////////////////////////////////////////// Setters / Update Functions //////////////////////////////////////////////////////////////*/ /// @notice maximum amount that can be ignored /// @dev only callable by LRT admin /// @param maxNegligibleAmount_ Maximum amount that can be ignored function setMaxNegligibleAmount(uint256 maxNegligibleAmount_) external onlyLRTAdmin { maxNegligibleAmount = maxNegligibleAmount_; emit MaxNegligibleAmountUpdated(maxNegligibleAmount_); } /// @notice update min amount to deposit /// @dev only callable by LRT admin /// @param minAmountToDeposit_ Minimum amount to deposit function setMinAmountToDeposit(uint256 minAmountToDeposit_) external onlyLRTAdmin { minAmountToDeposit = minAmountToDeposit_; emit MinAmountToDepositUpdated(minAmountToDeposit_); } /// @notice update max node delegator count /// @dev only callable by LRT admin /// @param maxNodeDelegatorLimit_ Maximum count of node delegator function updateMaxNodeDelegatorLimit(uint256 maxNodeDelegatorLimit_) external onlyLRTAdmin { if (maxNodeDelegatorLimit_ < nodeDelegatorQueue.length) { revert InvalidMaximumNodeDelegatorLimit(); } maxNodeDelegatorLimit = maxNodeDelegatorLimit_; emit MaxNodeDelegatorLimitUpdated(maxNodeDelegatorLimit); } /// @notice add new node delegator contract addresses /// @dev only callable by LRT admin /// @param nodeDelegatorContracts Array of NodeDelegator contract addresses function addNodeDelegatorContractToQueue(address[] calldata nodeDelegatorContracts) external onlyLRTAdmin { uint256 length = nodeDelegatorContracts.length; if (nodeDelegatorQueue.length + length > maxNodeDelegatorLimit) { revert MaximumNodeDelegatorLimitReached(); } for (uint256 i; i < length;) { UtilLib.checkNonZeroAddress(nodeDelegatorContracts[i]); // check if node delegator contract is already added and add it if not if (isNodeDelegator[nodeDelegatorContracts[i]] == 0) { nodeDelegatorQueue.push(nodeDelegatorContracts[i]); } isNodeDelegator[nodeDelegatorContracts[i]] = 1; unchecked { ++i; } } emit NodeDelegatorAddedinQueue(nodeDelegatorContracts); } /// @notice remove node delegator contract address from queue /// @dev only callable by LRT admin /// @param nodeDelegatorAddress NodeDelegator contract address function removeNodeDelegatorContractFromQueue(address nodeDelegatorAddress) external onlyLRTAdmin { _removeNodeDelegatorContractFromQueue(nodeDelegatorAddress); } /// @notice remove many node delegator contracts from queue /// @dev only callable by LRT admin /// @param nodeDelegatorContracts Array of NodeDelegator contract addresses function removeManyNodeDelegatorContractsFromQueue(address[] calldata nodeDelegatorContracts) external onlyLRTAdmin { uint256 length = nodeDelegatorContracts.length; for (uint256 i; i < length;) { _removeNodeDelegatorContractFromQueue(nodeDelegatorContracts[i]); unchecked { ++i; } } } /// @dev Triggers stopped state. Contract must not be paused. function pause() external onlyLRTManager { _pause(); } /// @dev Returns to normal state. Contract must be paused function unpause() external onlyLRTAdmin { _unpause(); } /*////////////////////////////////////////////////////////////// other write functions //////////////////////////////////////////////////////////////*/ /// @notice Approves the maximum amount of an asset to the LRTConverter contract /// @dev only supported assets can be deposited and only called by the LRT manager /// @param asset the asset to approve function maxApproveToLRTConverter(address asset) external onlySupportedAsset(asset) onlyLRTManager { address lrtConverterAddress = lrtConfig.getContract(LRTConstants.LRT_CONVERTER); IERC20(asset).approve(lrtConverterAddress, type(uint256).max); } /*////////////////////////////////////////////////////////////// view functions //////////////////////////////////////////////////////////////*/ /// @notice gets the total asset present in protocol /// @param asset Asset address /// @return totalAssetDeposit total asset present in protocol function getTotalAssetDeposits(address asset) public view override returns (uint256 totalAssetDeposit) { ( uint256 assetLyingInDepositPool, uint256 assetLyingInNDCs, uint256 assetStakedInEigenLayer, uint256 assetUnstakingFromEigenLayer, uint256 assetLyingInConverter, uint256 assetLyingUnstakingVault ) = getAssetDistributionData(asset); return ( assetLyingInDepositPool + assetLyingInNDCs + assetStakedInEigenLayer + assetUnstakingFromEigenLayer + assetLyingInConverter + assetLyingUnstakingVault ); } /// @notice gets the current limit of asset deposit /// @param asset Asset address /// @return currentLimit Current limit of asset deposit function getAssetCurrentLimit(address asset) public view override returns (uint256) { uint256 totalAssetDeposits = getTotalAssetDeposits(asset); if (totalAssetDeposits > lrtConfig.depositLimitByAsset(asset)) { return 0; } return lrtConfig.depositLimitByAsset(asset) - totalAssetDeposits; } /// @dev get node delegator queue /// @return nodeDelegatorQueue Array of node delegator contract addresses function getNodeDelegatorQueue() external view override returns (address[] memory) { return nodeDelegatorQueue; } /// @dev provides asset amount distribution data among depositPool, NDCs and eigenLayer /// @param asset the asset to get the total amount of /// @return assetLyingInDepositPool asset amount lying in this LRTDepositPool contract /// @return assetLyingInNDCs asset amount sum lying in all NDC contract /// @return assetStakedInEigenLayer asset amount deposited in eigen layer strategies through all NDCs /// @return assetUnstakingFromEigenLayer asset amount in delayed withdrawal from eigen layer strategies through all /// NDCs /// @return assetLyingInConverter asset value lying in converter /// @return assetLyingUnstakingVault asset amount lying in UnstakingVault function getAssetDistributionData(address asset) public view override onlySupportedAsset(asset) returns ( uint256 assetLyingInDepositPool, uint256 assetLyingInNDCs, uint256 assetStakedInEigenLayer, uint256 assetUnstakingFromEigenLayer, uint256 assetLyingInConverter, uint256 assetLyingUnstakingVault ) { if (asset == LRTConstants.ETH_TOKEN) { return getETHDistributionData(); } assetLyingInDepositPool = IERC20(asset).balanceOf(address(this)); uint256 ndcsCount = nodeDelegatorQueue.length; for (uint256 i; i < ndcsCount;) { assetLyingInNDCs += IERC20(asset).balanceOf(nodeDelegatorQueue[i]); assetStakedInEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getAssetBalance(asset); unchecked { ++i; } } address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); assetUnstakingFromEigenLayer = ILRTUnstakingVault(lrtUnstakingVault).getAssetsUnstaking(asset); assetLyingInConverter = 0; //assets in converter are accounted in there eth value => getETHDistributionData assetLyingUnstakingVault = IERC20(asset).balanceOf(lrtUnstakingVault); } /// @dev provides ETH amount distribution data among depositPool, NDCs and eigenLayer /// @dev rewards are not accounted here /// it will automatically be accounted once it is moved from feeReceiver/rewardReceiver to depositPool function getETHDistributionData() public view override returns ( uint256 ethLyingInDepositPool, uint256 ethLyingInNDCs, uint256 ethStakedInEigenLayer, uint256 ethUnstakingFromEigenLayer, uint256 ethLyingInConverter, uint256 ethLyingInUnstakingVault ) { ethLyingInDepositPool = address(this).balance; uint256 ndcsCount = nodeDelegatorQueue.length; for (uint256 i; i < ndcsCount;) { ethLyingInNDCs += nodeDelegatorQueue[i].balance; ethStakedInEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getETHEigenPodBalance(); unchecked { ++i; } } address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); ethUnstakingFromEigenLayer = ILRTUnstakingVault(lrtUnstakingVault).getAssetsUnstaking(LRTConstants.ETH_TOKEN); address lrtConverter = lrtConfig.getContract(LRTConstants.LRT_CONVERTER); ethLyingInConverter = ILRTConverter(lrtConverter).ethValueInWithdrawal(); ethLyingInUnstakingVault = lrtUnstakingVault.balance; } /// @notice View amount of rsETH to mint for given asset amount /// @param asset Asset address /// @param amount Asset amount /// @return rsethAmountToMint Amount of rseth to mint function getRsETHAmountToMint( address asset, uint256 amount ) public view override returns (uint256 rsethAmountToMint) { // setup oracle contract address lrtOracleAddress = lrtConfig.getContract(LRTConstants.LRT_ORACLE); ILRTOracle lrtOracle = ILRTOracle(lrtOracleAddress); // calculate rseth amount to mint based on asset amount and asset exchange rate rsethAmountToMint = (amount * lrtOracle.getAssetPrice(asset)) / lrtOracle.rsETHPrice(); } /// @notice get return amount for swapping ETH to asset that is accepted by LRTDepositPool /// @dev use LRTOracle to get price for toToken /// @param toAsset Asset address to swap to /// @param ethAmountToSend Eth amount to swap from /// @return returnAmount Return amount of toAsset function getSwapETHToAssetReturnAmount( address toAsset, uint256 ethAmountToSend ) public view returns (uint256 returnAmount) { address lrtOracleAddress = lrtConfig.getContract(LRTConstants.LRT_ORACLE); ILRTOracle lrtOracle = ILRTOracle(lrtOracleAddress); uint256 ethPricePerUint = 1e18; return ethPricePerUint * ethAmountToSend / lrtOracle.getAssetPrice(toAsset); } /*////////////////////////////////////////////////////////////// internal functions //////////////////////////////////////////////////////////////*/ /// @notice internal function to remove node delegator contract address from queue /// @param nodeDelegatorAddress NodeDelegator contract address function _removeNodeDelegatorContractFromQueue(address nodeDelegatorAddress) internal { // 1. check if node delegator contract is in queue and find Index uint256 ndcIndex = _getNDCIndex(nodeDelegatorAddress); // 2. revert if node delegator contract has any asset balances. // 2.1 check if NDC has native ETH balance in eigen layer or/and in itself. _checkResidueEthBalance(nodeDelegatorAddress); // 2.2 check if NDC has LST balance _checkResidueLSTBalance(nodeDelegatorAddress); // 3. remove node delegator contract from queue // 3.1 remove from isNodeDelegator mapping isNodeDelegator[nodeDelegatorAddress] = 0; // 3.2 remove from nodeDelegatorQueue nodeDelegatorQueue[ndcIndex] = nodeDelegatorQueue[nodeDelegatorQueue.length - 1]; nodeDelegatorQueue.pop(); emit NodeDelegatorRemovedFromQueue(nodeDelegatorAddress); } function _getNDCIndex(address nodeDelegatorAddress) internal view returns (uint256) { uint256 length = nodeDelegatorQueue.length; uint256 i; for (; i < length;) { if (nodeDelegatorQueue[i] == nodeDelegatorAddress) { return i; } unchecked { ++i; } } // If node delegator contract is not found in queue, revert revert NodeDelegatorNotFound(); } /// @dev reverts if NDC has native ETH balance in eigen layer or/and in itself. function _checkResidueEthBalance(address nodeDelegatorAddress) internal view { uint256 ndcEthBalance = INodeDelegator(nodeDelegatorAddress).getETHEigenPodBalance() + address(nodeDelegatorAddress).balance; if (ndcEthBalance > maxNegligibleAmount) { revert NodeDelegatorHasETH(); } } /// @dev reverts if NDC has LST balance function _checkResidueLSTBalance(address nodeDelegatorAddress) internal view { address[] memory supportedAssets = lrtConfig.getSupportedAssetList(); uint256 supportedAssetsLength = supportedAssets.length; uint256 assetBalance; for (uint256 i; i < supportedAssetsLength; ++i) { if (supportedAssets[i] == LRTConstants.ETH_TOKEN) { // this function only checks for residual LST balance continue; } assetBalance = IERC20(supportedAssets[i]).balanceOf(nodeDelegatorAddress) + INodeDelegator(nodeDelegatorAddress).getAssetBalance(supportedAssets[i]); if (assetBalance > maxNegligibleAmount) { revert NodeDelegatorHasAssetBalance(supportedAssets[i], assetBalance); } } } function _beforeDeposit( address asset, uint256 depositAmount, uint256 minRSETHAmountExpected ) private view returns (uint256 rsethAmountToMint) { if (depositAmount == 0 || depositAmount < minAmountToDeposit) { revert InvalidAmountToDeposit(); } if (_checkIfDepositAmountExceedesCurrentLimit(asset, depositAmount)) { revert MaximumDepositLimitReached(); } rsethAmountToMint = getRsETHAmountToMint(asset, depositAmount); if (rsethAmountToMint < minRSETHAmountExpected) { revert MinimumAmountToReceiveNotMet(); } } /// @notice checks if deposit amount exceeds current limit /// @param asset Asset address /// @param amount Asset amount /// @return bool true if deposit amount exceeds current limit function _checkIfDepositAmountExceedesCurrentLimit(address asset, uint256 amount) internal view returns (bool) { uint256 totalAssetDeposits = getTotalAssetDeposits(asset); if (asset == LRTConstants.ETH_TOKEN) { return (totalAssetDeposits > lrtConfig.depositLimitByAsset(asset)); } return (totalAssetDeposits + amount > lrtConfig.depositLimitByAsset(asset)); } /// @dev private function to mint rseth /// @param rsethAmountToMint Amount of rseth minted function _mintRsETH(uint256 rsethAmountToMint) private { address rsethToken = lrtConfig.rsETH(); // mint rseth for user IRSETH(rsethToken).mint(msg.sender, rsethAmountToMint); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; /// @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 getMin(uint256 a, uint256 b) internal pure returns (uint256) { if (a < b) return a; return b; } function getMax(uint256 a, uint256 b) internal pure returns (uint256) { if (a > b) return a; return b; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; library LRTConstants { //tokens //rETH token bytes32 public constant R_ETH_TOKEN = keccak256("R_ETH_TOKEN"); //stETH token bytes32 public constant ST_ETH_TOKEN = keccak256("ST_ETH_TOKEN"); //cbETH token bytes32 public constant CB_ETH_TOKEN = keccak256("CB_ETH_TOKEN"); //ETHX token bytes32 public constant ETHX_TOKEN = keccak256("ETHX_TOKEN"); //sfrxETH bytes32 public constant SFRX_ETH_TOKEN = keccak256("SFRX_ETH_TOKEN"); bytes32 public constant BEACON_CHAIN_ETH_STRATEGY = keccak256("BEACON_CHAIN_ETH_STRATEGY"); //contracts bytes32 public constant LRT_ORACLE = keccak256("LRT_ORACLE"); bytes32 public constant LRT_DEPOSIT_POOL = keccak256("LRT_DEPOSIT_POOL"); bytes32 public constant LRT_WITHDRAW_MANAGER = keccak256("LRT_WITHDRAW_MANAGER"); bytes32 public constant LRT_UNSTAKING_VAULT = keccak256("LRT_UNSTAKING_VAULT"); bytes32 public constant LRT_CONVERTER = keccak256("LRT_CONVERTER"); bytes32 public constant EIGEN_STRATEGY_MANAGER = keccak256("EIGEN_STRATEGY_MANAGER"); //Roles bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; bytes32 public constant MANAGER = keccak256("MANAGER"); bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); // updated library variables bytes32 public constant SFRXETH_TOKEN = keccak256("SFRXETH_TOKEN"); // add new vars below bytes32 public constant EIGEN_POD_MANAGER = keccak256("EIGEN_POD_MANAGER"); // native ETH as ERC20 for ease of implementation address public constant ETH_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; // Operator Role bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); // reward receiver contract bytes32 public constant REWARD_RECEIVER = keccak256("REWARD_RECEIVER"); // EigenLayer Delegation Manager bytes32 public constant EIGEN_DELEGATION_MANAGER = keccak256("EIGEN_DELEGATION_MANAGER"); uint256 public constant ONE_E_9 = 1e9; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import { UtilLib } from "./UtilLib.sol"; import { LRTConstants } from "./LRTConstants.sol"; import { ILRTConfig } from "../interfaces/ILRTConfig.sol"; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; /// @title LRTConfigRoleChecker - LRT Config Role Checker Contract /// @notice Handles LRT config role checks abstract contract LRTConfigRoleChecker { ILRTConfig public lrtConfig; // events event UpdatedLRTConfig(address indexed lrtConfig); // modifiers modifier onlyRole(bytes32 role) { if (!IAccessControl(address(lrtConfig)).hasRole(role, msg.sender)) { string memory roleStr = string(abi.encodePacked(role)); revert ILRTConfig.CallerNotLRTConfigAllowedRole(roleStr); } _; } modifier onlyLRTManager() { if (!IAccessControl(address(lrtConfig)).hasRole(LRTConstants.MANAGER, msg.sender)) { revert ILRTConfig.CallerNotLRTConfigManager(); } _; } modifier onlyLRTOperator() { if (!IAccessControl(address(lrtConfig)).hasRole(LRTConstants.OPERATOR_ROLE, msg.sender)) { revert ILRTConfig.CallerNotLRTConfigOperator(); } _; } modifier onlyLRTAdmin() { if (!IAccessControl(address(lrtConfig)).hasRole(LRTConstants.DEFAULT_ADMIN_ROLE, msg.sender)) { revert ILRTConfig.CallerNotLRTConfigAdmin(); } _; } modifier onlySupportedAsset(address asset) { if (!lrtConfig.isSupportedAsset(asset)) { revert ILRTConfig.AssetNotSupported(); } _; } // setters /// @notice Updates the LRT config contract /// @dev only callable by LRT admin /// @param lrtConfigAddr the new LRT config contract Address function updateLRTConfig(address lrtConfigAddr) external virtual onlyLRTAdmin { if (address(lrtConfig) != address(0)) revert ILRTConfig.ValueAlreadyInUse(); UtilLib.checkNonZeroAddress(lrtConfigAddr); lrtConfig = ILRTConfig(lrtConfigAddr); emit UpdatedLRTConfig(lrtConfigAddr); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; interface IRSETH is IERC20 { function mint(address account, uint256 amount) external; function burnFrom(address account, uint256 amount) external; function pause() external; function unpause() external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; interface ILRTOracle { // errors error AssetOracleNotSupported(); error RSETHPriceExceedsLimit(); // events event AssetPriceOracleUpdate(address indexed asset, address indexed priceOracle); event RsETHPriceUpdate(uint256 newPrice); event PricePercentageLimitUpdate(uint256 newLimit); // methods function getAssetPrice(address asset) external view returns (uint256); function assetPriceOracle(address asset) external view returns (address); function rsETHPrice() external view returns (uint256); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import { IStrategy, IERC20 } from "contracts/external/eigenlayer/interfaces/IStrategy.sol"; import { IEigenDelegationManager } from "contracts/external/eigenlayer/interfaces/IEigenDelegationManager.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface INodeDelegator { // event event AssetDepositIntoStrategy(address indexed asset, address indexed strategy, uint256 depositAmount); event ETHDepositFromDepositPool(uint256 depositAmount); event EigenPodCreated(address indexed eigenPod, address indexed podOwner); event ETHStaked(bytes valPubKey, uint256 amount); event WithdrawalQueued(uint256 nonce, address withdrawer, bytes32[] withdrawalRoots); event EthTransferred(address to, uint256 amount); event EigenLayerWithdrawalCompleted(address indexed depositor, uint256 nonce, address indexed caller); event ETHRewardsReceived(uint256 amount); event ETHExtraStakeToReceiveIncremented(uint256 amount); event ExtraStakeReceived(uint256 amount); event ETHRewardsWithdrawInitiated(uint256 amount); event ElSharesDelegated(address indexed elOperator); event RestakingActivated(); event ETHReceived(address indexed sender, uint256 amount); event Undelegated(); // errors error TokenTransferFailed(); error StrategyIsNotSetForAsset(); error InvalidETHSender(); error InvalidDepositRoot(bytes32 expectedDepositRoot, bytes32 actualDepositRoot); error StrategyMustNotBeBeaconChain(); error InsufficientStakedButUnverifiedNativeETH(); error InvalidWithdrawalData(); // getter function stakedButUnverifiedNativeETH() external view returns (uint256); // write functions function depositAssetIntoStrategy(address asset) external; function maxApproveToEigenStrategyManager(address asset) external; function initiateUnstaking( IStrategy[] calldata strategies, uint256[] calldata shares ) external returns (bytes32 withdrawalRoot); function completeUnstaking( IEigenDelegationManager.Withdrawal calldata withdrawal, IERC20[] calldata assets, uint256 middlewareTimesIndex ) external; // view functions function getAssetBalances() external view returns (address[] memory, uint256[] memory); function getAssetBalance(address asset) external view returns (uint256); function getETHEigenPodBalance() external view returns (uint256); function transferBackToLRTDepositPool(address asset, uint256 amount) external; function sendETHFromDepositPoolToNDC() external payable; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; interface ILRTDepositPool { //errors error InvalidAmountToDeposit(); error NotEnoughAssetToTransfer(); error MaximumDepositLimitReached(); error MaximumNodeDelegatorLimitReached(); error InvalidMaximumNodeDelegatorLimit(); error MinimumAmountToReceiveNotMet(); error NodeDelegatorNotFound(); error NodeDelegatorHasAssetBalance(address assetAddress, uint256 assetBalance); error NodeDelegatorHasETH(); error EthTransferFailed(); //events event MaxNodeDelegatorLimitUpdated(uint256 maxNodeDelegatorLimit); event NodeDelegatorAddedinQueue(address[] nodeDelegatorContracts); event NodeDelegatorRemovedFromQueue(address nodeDelegatorContracts); event AssetDeposit( address indexed depositor, address indexed asset, uint256 depositAmount, uint256 rsethMintAmount, string referralId ); event ETHDeposit(address indexed depositor, uint256 depositAmount, uint256 rsethMintAmount, string referralId); event MinAmountToDepositUpdated(uint256 minAmountToDeposit); event MaxNegligibleAmountUpdated(uint256 maxNegligibleAmount); event ETHSwappedForLST(uint256 ethAmount, address indexed toAsset, uint256 returnAmount); event EthTransferred(address to, uint256 amount); // functions function depositAsset( address asset, uint256 depositAmount, uint256 minRSETHAmountExpected, string calldata referralId ) external; function getSwapETHToAssetReturnAmount( address toAsset, uint256 ethAmountToSend ) external view returns (uint256 returnAmount); function getTotalAssetDeposits(address asset) external view returns (uint256); function getAssetCurrentLimit(address asset) external view returns (uint256); function getRsETHAmountToMint(address asset, uint256 depositAmount) external view returns (uint256); function addNodeDelegatorContractToQueue(address[] calldata nodeDelegatorContract) external; function transferAssetToNodeDelegator(uint256 ndcIndex, address asset, uint256 amount) external; function updateMaxNodeDelegatorLimit(uint256 maxNodeDelegatorLimit) external; function getNodeDelegatorQueue() external view returns (address[] memory); function getAssetDistributionData(address asset) external view returns ( uint256 assetLyingInDepositPool, uint256 assetLyingInNDCs, uint256 assetStakedInEigenLayer, uint256 assetUnstakingFromEigenLayer, uint256 assetLyingInConverter, uint256 assetLyingUnstakingVault ); function getETHDistributionData() external view returns ( uint256 ethLyingInDepositPool, uint256 ethLyingInNDCs, uint256 ethStakedInEigenLayer, uint256 ethUnstakingFromEigenLayer, uint256 ethLyingInConverter, uint256 ethLyingInUnstakingVault ); function isNodeDelegator(address nodeDelegatorContract) external view returns (uint256); // receivers function receiveFromRewardReceiver() external payable; function receiveFromLRTConverter() external payable; function receiveFromNodeDelegator() external payable; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import { IStrategy } from "contracts/external/eigenlayer/interfaces/IStrategy.sol"; import { IEigenDelegationManager } from "contracts/external/eigenlayer/interfaces/IEigenDelegationManager.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface ILRTUnstakingVault { error CallerNotLRTNodeDelegator(); error EthTransferFailed(); error CallerNotLRTWithdrawalManager(); event EthReceived(address sender, uint256 amount); // functions function sharesUnstaking(address asset) external view returns (uint256); function getAssetsUnstaking(address asset) external view returns (uint256); function balanceOf(address asset) external view returns (uint256); function addSharesUnstaking(address asset, uint256 amount) external; function reduceSharesUnstaking(address asset, uint256 amount) external; function redeem(address asset, uint256 amount) external; // receive functions function receiveFromLRTDepositPool() external payable; function receiveFromNodeDelegator() external payable; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import { IStrategy } from "contracts/external/eigenlayer/interfaces/IStrategy.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface ILRTWithdrawalManager { //errors error TokenTransferFailed(); error EthTransferFailed(); error InvalidAmountToWithdraw(); error ExceedAmountToWithdraw(); error WithdrawalLocked(); error WithdrawalDelayNotPassed(); error WithdrawalDelayTooSmall(); error NoPendingWithdrawals(); error AmountMustBeGreaterThanZero(); error StrategyNotSupported(); error RsETHPriceMustBeGreaterMinimum(uint256 rsEthPrice); error AssetPriceMustBeGreaterMinimum(uint256 assetPrice); struct WithdrawalRequest { uint256 rsETHUnstaked; uint256 expectedAssetAmount; uint256 withdrawalStartBlock; } //events event AssetWithdrawalQueued( address indexed withdrawer, address indexed asset, uint256 rsETHUnstaked, uint256 indexed userNonce ); event AssetWithdrawalFinalized( address indexed withdrawer, address indexed asset, uint256 amountBurned, uint256 amountReceived ); event EtherReceived(address indexed depositor, uint256 ethAmount, uint256 sharesAmount); event AssetUnlocked( address indexed asset, uint256 rsEthAmount, uint256 assetAmount, uint256 rsEThPrice, uint256 assetPrice ); event MinAmountToWithdrawUpdated(address asset, uint256 minRsEthAmountToWithdraw); event WithdrawalDelayBlocksUpdated(uint256 withdrawalDelayBlocks); // methods function getExpectedAssetAmount(address asset, uint256 amount) external view returns (uint256); function getAvailableAssetAmount(address asset) external view returns (uint256 assetAmount); function getUserWithdrawalRequest( address asset, address user, uint256 index ) external view returns (uint256 rsETHAmount, uint256 expectedAssetAmount, uint256 withdrawalStartBlock, uint256 userNonce); function initiateWithdrawal(address asset, uint256 withdrawAmount) external; function completeWithdrawal(address asset) external; function unlockQueue( address asset, uint256 index, uint256 minimumAssetPrice, uint256 minimumRsEthPrice ) external returns (uint256 rsETHBurned, uint256 assetAmountUnlocked); // receive functions function receiveFromLRTUnstakingVault() external payable; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import { IEigenDelegationManager } from "contracts/external/eigenlayer/interfaces/IEigenDelegationManager.sol"; interface ILRTConverter { error NotEnoughAssetToTransfer(); error TokenTransferFailed(); error InvalidWithdrawer(); error WithdrawalRootNotPending(); error WithdrawalRootAlreadyProcess(); error ConversionLimitReached(); error WithdrawalRootNotProcessed(); error MinimumExpectedReturnNotReached(); event ConvertedEigenlayerAssetToRsEth(address indexed reciever, uint256 rsethAmount, bytes32 withdrawalRoot); event ETHSwappedForLST(uint256 ethAmount, address indexed toAsset, uint256 returnAmount); event EthTransferred(address to, uint256 amount); function ethValueInWithdrawal() external view returns (uint256); function transferAssetFromDepositPool(address _asset, uint256 _amount) external; }
// 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.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.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: BUSL-1.1 pragma solidity 0.8.21; interface ILRTConfig { // Errors error ValueAlreadyInUse(); error AssetAlreadySupported(); error AssetNotSupported(); error CallerNotLRTConfigAdmin(); error CallerNotLRTConfigManager(); error CallerNotLRTConfigOperator(); error CallerNotLRTConfigAllowedRole(string role); error CannotUpdateStrategyAsItHasFundsNDCFunds(address ndc, uint256 amount); error InvalidMaxRewardAmount(); // Events event SetToken(bytes32 key, address indexed tokenAddr); event SetContract(bytes32 key, address indexed contractAddr); event AddedNewSupportedAsset(address indexed asset, uint256 depositLimit); event RemovedSupportedAsset(address indexed asset); event AssetDepositLimitUpdate(address indexed asset, uint256 depositLimit); event AssetStrategyUpdate(address indexed asset, address indexed strategy); event SetRSETH(address indexed rsETH); event UpdateMaxRewardAmount(uint256 maxRewardAmount); // methods function rsETH() external view returns (address); function assetStrategy(address asset) external view returns (address); function isSupportedAsset(address asset) external view returns (bool); function getLSTToken(bytes32 tokenId) external view returns (address); 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: 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: BUSL-1.1 pragma solidity >=0.5.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title Minimal interface for an `Strategy` contract. * @author Layr Labs, Inc. * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service * @notice Custom `Strategy` implementations may expand extensively on this interface. */ interface IStrategy { // packed struct for queued withdrawals; helps deal with stack-too-deep errors struct WithdrawerAndNonce { address withdrawer; uint96 nonce; } struct QueuedWithdrawal { IStrategy[] strategies; uint256[] shares; address depositor; WithdrawerAndNonce withdrawerAndNonce; uint32 withdrawalStartBlock; address delegatedAddress; } /** * @notice Used to deposit tokens into this Strategy * @param token is the ERC20 token being deposited * @param amount is the amount of token being deposited * @dev This function is only callable by the strategyManager contract. It is invoked inside of the * strategyManager's * `depositIntoStrategy` function, and individual share balances are recorded in the strategyManager as well. * @return newShares is the number of new shares issued at the current exchange ratio. */ function deposit(IERC20 token, uint256 amount) external returns (uint256); /** * @notice Used to withdraw tokens from this Strategy, to the `depositor`'s address * @param depositor is the address to receive the withdrawn funds * @param token is the ERC20 token being transferred out * @param amountShares is the amount of shares being withdrawn * @dev This function is only callable by the strategyManager contract. It is invoked inside of the * strategyManager's * other functions, and individual share balances are recorded in the strategyManager as well. */ function withdraw(address depositor, IERC20 token, uint256 amountShares) external; /** * @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy. * @notice In contrast to `sharesToUnderlyingView`, this function **may** make state modifications * @param amountShares is the amount of shares to calculate its conversion into the underlying token * @return The amount of underlying tokens corresponding to the input `amountShares` * @dev Implementation for these functions in particular may vary significantly for different strategies */ function sharesToUnderlying(uint256 amountShares) external returns (uint256); /** * @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy. * @notice In contrast to `underlyingToSharesView`, this function **may** make state modifications * @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares * @return The amount of underlying tokens corresponding to the input `amountShares` * @dev Implementation for these functions in particular may vary significantly for different strategies */ function underlyingToShares(uint256 amountUnderlying) external returns (uint256); /** * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in * this strategy. In contrast to `userUnderlyingView`, this function **may** make state modifications */ function userUnderlying(address user) external returns (uint256); /** * @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy. * @notice In contrast to `sharesToUnderlying`, this function guarantees no state modifications * @param amountShares is the amount of shares to calculate its conversion into the underlying token * @return The amount of shares corresponding to the input `amountUnderlying` * @dev Implementation for these functions in particular may vary significantly for different strategies */ function sharesToUnderlyingView(uint256 amountShares) external view returns (uint256); /** * @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy. * @notice In contrast to `underlyingToShares`, this function guarantees no state modifications * @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares * @return The amount of shares corresponding to the input `amountUnderlying` * @dev Implementation for these functions in particular may vary significantly for different strategies */ function underlyingToSharesView(uint256 amountUnderlying) external view returns (uint256); /** * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in * this strategy. In contrast to `userUnderlying`, this function guarantees no state modifications */ function userUnderlyingView(address user) external view returns (uint256); /// @notice The underlying token for shares in this Strategy function underlyingToken() external view returns (IERC20); /// @notice The total number of extant shares in this Strategy function totalShares() external view returns (uint256); /// @notice Returns either a brief string explaining the strategy's goal & purpose, or a link to metadata that /// explains in more detail. function explanation() external view returns (string memory); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import "./IStrategy.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 IEigenDelegationManager { // @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); function pendingWithdrawals(bytes32 withdrawalRoot) external view returns (bool); /** * @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 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); // @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 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 Delegates from `staker` to `operator`. * @dev requires that: * 1) if `staker` is an EOA, then `signature` is valid ECDSA signature from `staker`, indicating their intention for * this action * 2) if `staker` is a contract, then `signature` must will be checked according to EIP-1271 */ function delegateToBySignature(address staker, address operator, uint256 expiry, bytes memory signature) external; /** * @notice Returns the number of actively-delegatable shares a staker has across all strategies. * @dev Returns two empty arrays in the case that the Staker has no actively-delegateable shares. */ function getDelegatableShares(address staker) external view returns (IStrategy[] memory, uint256[] memory); /// @notice Returns 'true' if `staker` is *not* actively delegated, and 'false' otherwise. function isNotDelegated(address staker) external view returns (bool); }
// 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 (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (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) (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: 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); } } }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "eth-gas-reporter/=node_modules/eth-gas-reporter/", "hardhat/=node_modules/hardhat/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/", "solidity-code-metrics/=node_modules/solidity-code-metrics/" ], "optimizer": { "enabled": true, "runs": 10000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "shanghai", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AssetNotSupported","type":"error"},{"inputs":[],"name":"CallerNotLRTConfigAdmin","type":"error"},{"inputs":[],"name":"CallerNotLRTConfigManager","type":"error"},{"inputs":[],"name":"EthTransferFailed","type":"error"},{"inputs":[],"name":"InvalidAmountToDeposit","type":"error"},{"inputs":[],"name":"InvalidMaximumNodeDelegatorLimit","type":"error"},{"inputs":[],"name":"MaximumDepositLimitReached","type":"error"},{"inputs":[],"name":"MaximumNodeDelegatorLimitReached","type":"error"},{"inputs":[],"name":"MinimumAmountToReceiveNotMet","type":"error"},{"inputs":[{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"uint256","name":"assetBalance","type":"uint256"}],"name":"NodeDelegatorHasAssetBalance","type":"error"},{"inputs":[],"name":"NodeDelegatorHasETH","type":"error"},{"inputs":[],"name":"NodeDelegatorNotFound","type":"error"},{"inputs":[],"name":"NotEnoughAssetToTransfer","type":"error"},{"inputs":[],"name":"ValueAlreadyInUse","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rsethMintAmount","type":"uint256"},{"indexed":false,"internalType":"string","name":"referralId","type":"string"}],"name":"AssetDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rsethMintAmount","type":"uint256"},{"indexed":false,"internalType":"string","name":"referralId","type":"string"}],"name":"ETHDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"ethAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"toAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"returnAmount","type":"uint256"}],"name":"ETHSwappedForLST","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EthTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxNegligibleAmount","type":"uint256"}],"name":"MaxNegligibleAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxNodeDelegatorLimit","type":"uint256"}],"name":"MaxNodeDelegatorLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minAmountToDeposit","type":"uint256"}],"name":"MinAmountToDepositUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"nodeDelegatorContracts","type":"address[]"}],"name":"NodeDelegatorAddedinQueue","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"nodeDelegatorContracts","type":"address"}],"name":"NodeDelegatorRemovedFromQueue","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","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":"lrtConfig","type":"address"}],"name":"UpdatedLRTConfig","type":"event"},{"inputs":[{"internalType":"address[]","name":"nodeDelegatorContracts","type":"address[]"}],"name":"addNodeDelegatorContractToQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"uint256","name":"minRSETHAmountExpected","type":"uint256"},{"internalType":"string","name":"referralId","type":"string"}],"name":"depositAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minRSETHAmountExpected","type":"uint256"},{"internalType":"string","name":"referralId","type":"string"}],"name":"depositETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getAssetCurrentLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getAssetDistributionData","outputs":[{"internalType":"uint256","name":"assetLyingInDepositPool","type":"uint256"},{"internalType":"uint256","name":"assetLyingInNDCs","type":"uint256"},{"internalType":"uint256","name":"assetStakedInEigenLayer","type":"uint256"},{"internalType":"uint256","name":"assetUnstakingFromEigenLayer","type":"uint256"},{"internalType":"uint256","name":"assetLyingInConverter","type":"uint256"},{"internalType":"uint256","name":"assetLyingUnstakingVault","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getETHDistributionData","outputs":[{"internalType":"uint256","name":"ethLyingInDepositPool","type":"uint256"},{"internalType":"uint256","name":"ethLyingInNDCs","type":"uint256"},{"internalType":"uint256","name":"ethStakedInEigenLayer","type":"uint256"},{"internalType":"uint256","name":"ethUnstakingFromEigenLayer","type":"uint256"},{"internalType":"uint256","name":"ethLyingInConverter","type":"uint256"},{"internalType":"uint256","name":"ethLyingInUnstakingVault","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNodeDelegatorQueue","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getRsETHAmountToMint","outputs":[{"internalType":"uint256","name":"rsethAmountToMint","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"toAsset","type":"address"},{"internalType":"uint256","name":"ethAmountToSend","type":"uint256"}],"name":"getSwapETHToAssetReturnAmount","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getTotalAssetDeposits","outputs":[{"internalType":"uint256","name":"totalAssetDeposit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"lrtConfigAddr","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isNodeDelegator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lrtConfig","outputs":[{"internalType":"contract ILRTConfig","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"maxApproveToLRTConverter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxNegligibleAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxNodeDelegatorLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minAmountToDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"nodeDelegatorQueue","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"receiveFromLRTConverter","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"receiveFromNodeDelegator","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"receiveFromRewardReceiver","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"nodeDelegatorContracts","type":"address[]"}],"name":"removeManyNodeDelegatorContractsFromQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nodeDelegatorAddress","type":"address"}],"name":"removeNodeDelegatorContractFromQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxNegligibleAmount_","type":"uint256"}],"name":"setMaxNegligibleAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minAmountToDeposit_","type":"uint256"}],"name":"setMinAmountToDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"toAsset","type":"address"},{"internalType":"uint256","name":"minToAssetAmount","type":"uint256"}],"name":"swapETHForAssetWithinDepositPool","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferAssetToLRTUnstakingVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"ndcIndex","type":"uint256"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferAssetToNodeDelegator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferETHToLRTUnstakingVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"ndcIndex","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferETHToNodeDelegator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lrtConfigAddr","type":"address"}],"name":"updateLRTConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxNodeDelegatorLimit_","type":"uint256"}],"name":"updateMaxNodeDelegatorLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405234801562000010575f80fd5b506200001b62000021565b620000ec565b5f54600160a81b900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f54600160a01b900460ff90811614620000ea575f805460ff60a01b191660ff60a01b17905560405160ff81527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61461a80620000fa5f395ff3fe60806040526004361061022c575f3560e01c8063884c105611610131578063c3ae1766116100ac578063db4380681161007c578063e356edb411610062578063e356edb414610256578063f1650a46146105f8578063fe6e13e614610616575f80fd5b8063db43806814610256578063e1736cba146105d9575f80fd5b8063c3ae17661461057a578063c4d66de814610599578063ce895a2f146105b8578063d3e445c214610256575f80fd5b8063b2628fdf11610101578063ba5bb442116100e7578063ba5bb44214610527578063bb3cfdac14610546578063c14db92714610565575f80fd5b8063b2628fdf146104bc578063b4a92e4714610508575f80fd5b8063884c10561461044c5780638cb20e6f1461046b578063a3185ed01461048a578063a9f0c9bc146104a9575f80fd5b806352c4889f116101c157806372c51c0b116101915780637969afa0116101775780637969afa0146103e25780637a0dace2146104015780638456cb5914610438575f80fd5b806372c51c0b146103ba578063778fbe60146103cd575f80fd5b806352c4889f1461033b5780635c975abb1461035a57806368182f9f1461037c5780636bf8b4751461039b575f80fd5b80631d572d55116101fc5780631d572d55146102b55780633f4ba83a146102d45780634337a95c146102e85780634f444d2514610310575f80fd5b806302570b831461023757806309bb0f571461025857806315864e0a1461027757806319304ccf14610296575f80fd5b3661023357005b5f80fd5b348015610242575f80fd5b50610256610251366004613fbf565b61062a565b005b348015610263575f80fd5b50610256610272366004613fda565b6108fe565b348015610282575f80fd5b50610256610291366004613fbf565b610a1c565b3480156102a1575f80fd5b506102566102b0366004613ff1565b610b6c565b3480156102c0575f80fd5b506102566102cf366004613ff1565b610de6565b3480156102df575f80fd5b50610256610ece565b3480156102f3575f80fd5b506102fd609b5481565b6040519081526020015b60405180910390f35b34801561031b575f80fd5b506102fd61032a366004613fbf565b60996020525f908152604090205481565b348015610346575f80fd5b506102fd610355366004613fbf565b610f7e565b348015610365575f80fd5b5060335460ff166040519015158152602001610307565b348015610387575f80fd5b50610256610396366004613fda565b610fde565b3480156103a6575f80fd5b506102566103b5366004613fbf565b6110b9565b6102566103c83660046140a5565b61116b565b3480156103d8575f80fd5b506102fd60985481565b3480156103ed575f80fd5b506102566103fc3660046140ed565b6111fd565b34801561040c575f80fd5b5061042061041b366004613fda565b6113b3565b6040516001600160a01b039091168152602001610307565b348015610443575f80fd5b506102566113db565b348015610457575f80fd5b506102fd610466366004613fbf565b6114a8565b348015610476575f80fd5b50610256610485366004613fda565b6115dd565b348015610495575f80fd5b506102fd6104a436600461410d565b6116b8565b6102566104b736600461410d565b61180c565b3480156104c7575f80fd5b506104db6104d6366004613fbf565b611b2f565b604080519687526020870195909552938501929092526060840152608083015260a082015260c001610307565b348015610513575f80fd5b50610256610522366004614137565b611ff9565b348015610532575f80fd5b506102fd61054136600461410d565b6121c5565b348015610551575f80fd5b5061025661056036600461410d565b61236c565b348015610570575f80fd5b506102fd60975481565b348015610585575f80fd5b5061025661059436600461416c565b6125b8565b3480156105a4575f80fd5b506102566105b3366004613fbf565b612712565b3480156105c3575f80fd5b506105cc612967565b60405161030791906141d1565b3480156105e4575f80fd5b506102566105f3366004613fda565b6129c7565b348015610603575f80fd5b505f54610420906001600160a01b031681565b348015610621575f80fd5b506104db612bdd565b5f546040517f9be918e60000000000000000000000000000000000000000000000000000000081526001600160a01b03808416600483015283921690639be918e690602401602060405180830381865afa15801561068a573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106ae919061421d565b6106e4576040517f981a2a2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f54604051632474521560e21b81527faf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c60048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa15801561074f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610773919061421d565b6107a9576040517f210d9c6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527f305e5896d422923741b53f048a145a568046f2ae0bba25aa944a6839a26690ef60048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015610828573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061084c919061424c565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248301529192509084169063095ea7b3906044016020604051808303815f875af11580156108d4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108f8919061421d565b50505050565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa15801561094a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061096e919061421d565b6109a4576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609a548110156109e0576040517fe1a3dd9200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60978190556040518181527f44a9f72c31db7b99a131a49de95fe2420c60e9fe9bff0a1a13d47b4af14566b4906020015b60405180910390a150565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa158015610a68573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8c919061421d565b610ac2576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f546001600160a01b031615610b04576040517f18e6d51900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b0d81612f37565b5f80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117825560405190917f9cf19cefd9aab739c33b95716ee3f3f921f219dc6d7aae25e1f9497b3788915091a250565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa158015610bb8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bdc919061421d565b610c12576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609754609a54829190610c26908390614294565b1115610c5e576040517f9aca5e2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b81811015610da757610c97848483818110610c7d57610c7d6142a7565b9050602002016020810190610c929190613fbf565b612f37565b60995f858584818110610cac57610cac6142a7565b9050602002016020810190610cc19190613fbf565b6001600160a01b03166001600160a01b031681526020019081526020015f20545f03610d5a57609a848483818110610cfb57610cfb6142a7565b9050602002016020810190610d109190613fbf565b81546001810183555f928352602090922090910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039092169190911790555b600160995f868685818110610d7157610d716142a7565b9050602002016020810190610d869190613fbf565b6001600160a01b0316815260208101919091526040015f2055600101610c60565b507f7c2453850055cd8625ebfc0116c7b3eec5d5e6b0b584e69a719089e22f461d638383604051610dd99291906142d4565b60405180910390a1505050565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa158015610e32573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e56919061421d565b610e8c576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805f5b818110156108f857610ec6848483818110610eac57610eac6142a7565b9050602002016020810190610ec19190613fbf565b612f77565b600101610e8f565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa158015610f1a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f3e919061421d565b610f74576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f7c6130c7565b565b5f805f805f805f610f8e88611b2f565b95509550955095509550955080828486888a610faa9190614294565b610fb49190614294565b610fbe9190614294565b610fc89190614294565b610fd29190614294565b98975050505050505050565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa15801561102a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061104e919061421d565b611084576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609b8190556040518181527fae34faed95cd4022e6c7e9bb4219e7f69d343fcf210c8893cb520fa603e7d17790602001610a11565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa158015611105573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611129919061421d565b61115f576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61116881612f77565b50565b611173613137565b61117b613190565b5f61119b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee34866131e3565b90506111a6816132b0565b336001600160a01b03167f8b0422d41caf5eb583695377e98b5041a1d241a7c80483cf182b1311c48c93b7348386866040516111e59493929190614321565b60405180910390a2506111f86001606555565b505050565b611205613137565b5f54604051632474521560e21b81527faf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c60048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015611270573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611294919061421d565b6112ca576040517f210d9c6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f609a83815481106112de576112de6142a7565b5f918252602082200154604080517f5e68300700000000000000000000000000000000000000000000000000000000815290516001600160a01b0390921693508392635e683007928692600480820193929182900301818588803b158015611344575f80fd5b505af1158015611356573d5f803e3d5ffd5b5050604080516001600160a01b0386168152602081018790527fcec1f18c3ab8ddaaa107a1591e3c369667eec613626611a8deaedef43069fcdd945001915061139c9050565b60405180910390a1506113af6001606555565b5050565b609a81815481106113c2575f80fd5b5f918252602090912001546001600160a01b0316905081565b5f54604051632474521560e21b81527faf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c60048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015611446573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061146a919061421d565b6114a0576040517f210d9c6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f7c6133a5565b5f806114b383610f7e565b5f546040517f435756480000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152929350911690634357564890602401602060405180830381865afa158015611515573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611539919061437b565b81111561154857505f92915050565b5f546040517f435756480000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015283921690634357564890602401602060405180830381865afa1580156115a8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115cc919061437b565b6115d69190614392565b9392505050565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa158015611629573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061164d919061421d565b611683576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60988190556040518181527f1bba2f1175afe384c3b2efde45f19740b744459c61a7700994196fe4d84af17690602001610a11565b5f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527f0900d19e2faab4e79535bcc1cfdb63996d43c8e38d9a260cf2b01e820b5f84d4600482015282916001600160a01b03169063e16c7d9890602401602060405180830381865afa158015611737573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061175b919061424c565b6040517fb3596f070000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301529192508291670de0b6b3a7640000919083169063b3596f0790602401602060405180830381865afa1580156117c8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117ec919061437b565b6117f686836143a5565b61180091906143bc565b93505050505b92915050565b5f54604051632474521560e21b81527faf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c60048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015611877573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061189b919061421d565b6118d1576040517f210d9c6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f546040517f9be918e60000000000000000000000000000000000000000000000000000000081526001600160a01b03808516600483015284921690639be918e690602401602060405180830381865afa158015611931573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611955919061421d565b61198b576040517f981a2a2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b345f61199785836116b8565b905083811080611a2557506040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038716906370a0823190602401602060405180830381865afa1580156119ff573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a23919061437b565b105b15611a5c576040517f21d9b3bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018290526001600160a01b0386169063a9059cbb906044016020604051808303815f875af1158015611abf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ae3919061421d565b5060408051838152602081018390526001600160a01b038716917fdfcec2e5d46add579374c8b094c104992049258e32c4b148984940d21f023308910160405180910390a25050505050565b5f80546040517f9be918e60000000000000000000000000000000000000000000000000000000081526001600160a01b03808516600483015283928392839283928392899290911690639be918e690602401602060405180830381865afa158015611b9c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bc0919061421d565b611bf6576040517f981a2a2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03891601611c3f57611c2e612bdd565b965096509650965096509650611fef565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038916906370a0823190602401602060405180830381865afa158015611c9a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cbe919061437b565b609a549097505f5b81811015611e3957896001600160a01b03166370a08231609a8381548110611cf057611cf06142a7565b5f9182526020909120015460405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039091166004820152602401602060405180830381865afa158015611d55573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d79919061437b565b611d839089614294565b9750609a8181548110611d9857611d986142a7565b5f918252602090912001546040517f5373433f0000000000000000000000000000000000000000000000000000000081526001600160a01b038c8116600483015290911690635373433f90602401602060405180830381865afa158015611e01573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e25919061437b565b611e2f9088614294565b9650600101611cc6565b505f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527fe1defbdba228c2f450cc8f3382e0fb463dd4233b2b59c3d3ed9e518e77222ed360048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015611eb9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611edd919061424c565b6040517fc5bac6510000000000000000000000000000000000000000000000000000000081526001600160a01b038c811660048301529192509082169063c5bac65190602401602060405180830381865afa158015611f3e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f62919061437b565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301529197505f9650908b16906370a0823190602401602060405180830381865afa158015611fc6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fea919061437b565b935050505b5091939550919395565b612001613137565b5f54604051632474521560e21b81527faf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c60048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa15801561206c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612090919061421d565b6120c6576040517f210d9c6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f546040517f9be918e60000000000000000000000000000000000000000000000000000000081526001600160a01b03808516600483015284921690639be918e690602401602060405180830381865afa158015612126573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061214a919061421d565b612180576040517f981a2a2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f609a8581548110612194576121946142a7565b5f918252602090912001546001600160a01b0390811691506121b99085168285613400565b50506111f86001606555565b5f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527f0900d19e2faab4e79535bcc1cfdb63996d43c8e38d9a260cf2b01e820b5f84d4600482015282916001600160a01b03169063e16c7d9890602401602060405180830381865afa158015612244573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612268919061424c565b90505f819050806001600160a01b031663b4b464346040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122aa573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122ce919061437b565b6040517fb3596f070000000000000000000000000000000000000000000000000000000081526001600160a01b03878116600483015283169063b3596f0790602401602060405180830381865afa15801561232b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061234f919061437b565b61235990866143a5565b61236391906143bc565b95945050505050565b612374613137565b5f54604051632474521560e21b81527faf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c60048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa1580156123df573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612403919061421d565b612439576040517f210d9c6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f546040517f9be918e60000000000000000000000000000000000000000000000000000000081526001600160a01b03808516600483015284921690639be918e690602401602060405180830381865afa158015612499573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124bd919061421d565b6124f3576040517f981a2a2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527fe1defbdba228c2f450cc8f3382e0fb463dd4233b2b59c3d3ed9e518e77222ed360048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612572573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612596919061424c565b90506125ac6001600160a01b0385168285613400565b50506113af6001606555565b6125c0613137565b6125c8613190565b5f546040517f9be918e60000000000000000000000000000000000000000000000000000000081526001600160a01b03808816600483015287921690639be918e690602401602060405180830381865afa158015612628573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061264c919061421d565b612682576040517f981a2a2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61268e8787876131e3565b90506126a56001600160a01b0388163330896134c7565b6126ae816132b0565b866001600160a01b0316336001600160a01b03167f07c31fccf51996f0f4ea01c3a55191786b3a8cd89f696db4d42adaa99b0e15f1888488886040516126f79493929190614321565b60405180910390a3505061270b6001606555565b5050505050565b5f547501000000000000000000000000000000000000000000900460ff161580801561275b57505f5460017401000000000000000000000000000000000000000090910460ff16105b8061278c5750303b15801561278c57505f5474010000000000000000000000000000000000000000900460ff166001145b6128035760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b5f80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790558015612887575f80547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1675010000000000000000000000000000000000000000001790555b61289082612f37565b612898613518565b6128a06135b0565b600a6097555f80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038416908117825560405190917f9cf19cefd9aab739c33b95716ee3f3f921f219dc6d7aae25e1f9497b3788915091a280156113af575f80547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15050565b6060609a8054806020026020016040519081016040528092919081815260200182805480156129bd57602002820191905f5260205f20905b81546001600160a01b0316815260019091019060200180831161299f575b5050505050905090565b6129cf613137565b5f54604051632474521560e21b81527faf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c60048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015612a3a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a5e919061421d565b612a94576040517f210d9c6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527fe1defbdba228c2f450cc8f3382e0fb463dd4233b2b59c3d3ed9e518e77222ed360048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612b13573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b37919061424c565b9050806001600160a01b0316635f3cbfd4836040518263ffffffff1660e01b81526004015f604051808303818588803b158015612b72575f80fd5b505af1158015612b84573d5f803e3d5ffd5b5050604080516001600160a01b0386168152602081018790527fcec1f18c3ab8ddaaa107a1591e3c369667eec613626611a8deaedef43069fcdd9450019150612bca9050565b60405180910390a1506111686001606555565b609a5447905f908190819081908190815b81811015612cd957609a8181548110612c0957612c096142a7565b5f91825260209091200154612c28906001600160a01b03163188614294565b9650609a8181548110612c3d57612c3d6142a7565b5f9182526020918290200154604080517f497edda000000000000000000000000000000000000000000000000000000000815290516001600160a01b039092169263497edda0926004808401938290030181865afa158015612ca1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cc5919061437b565b612ccf9087614294565b9550600101612bee565b505f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527fe1defbdba228c2f450cc8f3382e0fb463dd4233b2b59c3d3ed9e518e77222ed360048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612d59573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d7d919061424c565b6040517fc5bac65100000000000000000000000000000000000000000000000000000000815273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60048201529091506001600160a01b0382169063c5bac65190602401602060405180830381865afa158015612def573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e13919061437b565b5f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527f305e5896d422923741b53f048a145a568046f2ae0bba25aa944a6839a26690ef600482015292975090916001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612e97573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ebb919061424c565b9050806001600160a01b0316636a4c410d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ef9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f1d919061437b565b9450816001600160a01b0316319350505050909192939495565b6001600160a01b038116611168576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f612f8182613648565b9050612f8c826136ce565b612f9582613782565b6001600160a01b0382165f90815260996020526040812055609a8054612fbd90600190614392565b81548110612fcd57612fcd6142a7565b5f91825260209091200154609a80546001600160a01b039092169183908110612ff857612ff86142a7565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550609a805480613034576130346143f4565b5f8281526020908190207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff908301810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690559091019091556040516001600160a01b03841681527fb17adb7f863ad4dced68bd4045e81e087cb8c5b536bf2dbda6c8176e5fc593b9910161295b565b6130cf613a28565b603380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6002606554036131895760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016127fa565b6002606555565b60335460ff1615610f7c5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016127fa565b5f8215806131f2575060985483105b15613229576040517f91c6ba0200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6132338484613a7a565b1561326a576040517f1751ef8300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61327484846121c5565b9050818110156115d6576040517f1ec9a89400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f9054906101000a90046001600160a01b03166001600160a01b031662b83bce6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156132ff573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613323919061424c565b6040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820152602481018490529091506001600160a01b038216906340c10f19906044015f604051808303815f87803b158015613384575f80fd5b505af1158015613396573d5f803e3d5ffd5b505050505050565b6001606555565b6133ad613190565b603380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861311a3390565b6040516001600160a01b0383166024820152604481018290526111f89084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613bda565b6040516001600160a01b03808516602483015283166044820152606481018290526108f89085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401613445565b5f547501000000000000000000000000000000000000000000900460ff166135a85760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016127fa565b610f7c613cc0565b5f547501000000000000000000000000000000000000000000900460ff166136405760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016127fa565b610f7c613d7a565b609a545f90815b8181101561369c57836001600160a01b0316609a8281548110613674576136746142a7565b5f918252602090912001546001600160a01b031603613694579392505050565b60010161364f565b6040517fa5cddd8f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f816001600160a01b031631826001600160a01b031663497edda06040518163ffffffff1660e01b8152600401602060405180830381865afa158015613716573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061373a919061437b565b6137449190614294565b9050609b548111156113af576040517f706a3d5300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f9054906101000a90046001600160a01b03166001600160a01b031663770672a66040518163ffffffff1660e01b81526004015f60405180830381865afa1580156137d1573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052613816919081019061444e565b80519091505f805b8281101561270b5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b0316848281518110613856576138566142a7565b60200260200101516001600160a01b03160315613a1857846001600160a01b0316635373433f85838151811061388e5761388e6142a7565b60200260200101516040518263ffffffff1660e01b81526004016138c191906001600160a01b0391909116815260200190565b602060405180830381865afa1580156138dc573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613900919061437b565b848281518110613912576139126142a7565b60209081029190910101516040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152909116906370a0823190602401602060405180830381865afa15801561397b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061399f919061437b565b6139a99190614294565b9150609b54821115613a18578381815181106139c7576139c76142a7565b6020026020010151826040517fef008f080000000000000000000000000000000000000000000000000000000081526004016127fa9291906001600160a01b03929092168252602082015260400190565b613a2181614520565b905061381e565b60335460ff16610f7c5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016127fa565b5f80613a8584610f7e565b90507fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03851601613b43575f546040517f435756480000000000000000000000000000000000000000000000000000000081526001600160a01b03868116600483015290911690634357564890602401602060405180830381865afa158015613b17573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b3b919061437b565b109050611806565b5f546040517f435756480000000000000000000000000000000000000000000000000000000081526001600160a01b03868116600483015290911690634357564890602401602060405180830381865afa158015613ba3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613bc7919061437b565b613bd18483614294565b11949350505050565b5f613c2e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613e0a9092919063ffffffff16565b905080515f1480613c4e575080806020019051810190613c4e919061421d565b6111f85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016127fa565b5f547501000000000000000000000000000000000000000000900460ff16613d505760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016127fa565b603380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b5f547501000000000000000000000000000000000000000000900460ff1661339e5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016127fa565b6060613e1884845f85613e20565b949350505050565b606082471015613e985760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016127fa565b5f80866001600160a01b03168587604051613eb39190614579565b5f6040518083038185875af1925050503d805f8114613eed576040519150601f19603f3d011682016040523d82523d5f602084013e613ef2565b606091505b5091509150613f0387838387613f0e565b979650505050505050565b60608315613f7c5782515f03613f75576001600160a01b0385163b613f755760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016127fa565b5081613e18565b613e188383815115613f915781518083602001fd5b8060405162461bcd60e51b81526004016127fa9190614594565b6001600160a01b0381168114611168575f80fd5b5f60208284031215613fcf575f80fd5b81356115d681613fab565b5f60208284031215613fea575f80fd5b5035919050565b5f8060208385031215614002575f80fd5b823567ffffffffffffffff80821115614019575f80fd5b818501915085601f83011261402c575f80fd5b81358181111561403a575f80fd5b8660208260051b850101111561404e575f80fd5b60209290920196919550909350505050565b5f8083601f840112614070575f80fd5b50813567ffffffffffffffff811115614087575f80fd5b60208301915083602082850101111561409e575f80fd5b9250929050565b5f805f604084860312156140b7575f80fd5b83359250602084013567ffffffffffffffff8111156140d4575f80fd5b6140e086828701614060565b9497909650939450505050565b5f80604083850312156140fe575f80fd5b50508035926020909101359150565b5f806040838503121561411e575f80fd5b823561412981613fab565b946020939093013593505050565b5f805f60608486031215614149575f80fd5b83359250602084013561415b81613fab565b929592945050506040919091013590565b5f805f805f60808688031215614180575f80fd5b853561418b81613fab565b94506020860135935060408601359250606086013567ffffffffffffffff8111156141b4575f80fd5b6141c088828901614060565b969995985093965092949392505050565b602080825282518282018190525f9190848201906040850190845b818110156142115783516001600160a01b0316835292840192918401916001016141ec565b50909695505050505050565b5f6020828403121561422d575f80fd5b815180151581146115d6575f80fd5b805161424781613fab565b919050565b5f6020828403121561425c575f80fd5b81516115d681613fab565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561180657611806614267565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60208082528181018390525f908460408401835b868110156143165782356142fb81613fab565b6001600160a01b0316825291830191908301906001016142e8565b509695505050505050565b84815283602082015260606040820152816060820152818360808301375f818301608090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01601019392505050565b5f6020828403121561438b575f80fd5b5051919050565b8181038181111561180657611806614267565b808202811582820484141761180657611806614267565b5f826143ef577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f602080838503121561445f575f80fd5b825167ffffffffffffffff80821115614476575f80fd5b818501915085601f830112614489575f80fd5b81518181111561449b5761449b614421565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811085821117156144de576144de614421565b6040529182528482019250838101850191888311156144fb575f80fd5b938501935b82851015610fd2576145118561423c565b84529385019392850192614500565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361455057614550614267565b5060010190565b5f5b83811015614571578181015183820152602001614559565b50505f910152565b5f825161458a818460208701614557565b9190910192915050565b602081525f82518060208401526145b2816040850160208701614557565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea264697066735822122029c5c73aaf03e1de577c6c72cdc480afd19aeff8d5b00d7ad850c6c554036b5c64736f6c63430008150033
Deployed Bytecode
0x60806040526004361061022c575f3560e01c8063884c105611610131578063c3ae1766116100ac578063db4380681161007c578063e356edb411610062578063e356edb414610256578063f1650a46146105f8578063fe6e13e614610616575f80fd5b8063db43806814610256578063e1736cba146105d9575f80fd5b8063c3ae17661461057a578063c4d66de814610599578063ce895a2f146105b8578063d3e445c214610256575f80fd5b8063b2628fdf11610101578063ba5bb442116100e7578063ba5bb44214610527578063bb3cfdac14610546578063c14db92714610565575f80fd5b8063b2628fdf146104bc578063b4a92e4714610508575f80fd5b8063884c10561461044c5780638cb20e6f1461046b578063a3185ed01461048a578063a9f0c9bc146104a9575f80fd5b806352c4889f116101c157806372c51c0b116101915780637969afa0116101775780637969afa0146103e25780637a0dace2146104015780638456cb5914610438575f80fd5b806372c51c0b146103ba578063778fbe60146103cd575f80fd5b806352c4889f1461033b5780635c975abb1461035a57806368182f9f1461037c5780636bf8b4751461039b575f80fd5b80631d572d55116101fc5780631d572d55146102b55780633f4ba83a146102d45780634337a95c146102e85780634f444d2514610310575f80fd5b806302570b831461023757806309bb0f571461025857806315864e0a1461027757806319304ccf14610296575f80fd5b3661023357005b5f80fd5b348015610242575f80fd5b50610256610251366004613fbf565b61062a565b005b348015610263575f80fd5b50610256610272366004613fda565b6108fe565b348015610282575f80fd5b50610256610291366004613fbf565b610a1c565b3480156102a1575f80fd5b506102566102b0366004613ff1565b610b6c565b3480156102c0575f80fd5b506102566102cf366004613ff1565b610de6565b3480156102df575f80fd5b50610256610ece565b3480156102f3575f80fd5b506102fd609b5481565b6040519081526020015b60405180910390f35b34801561031b575f80fd5b506102fd61032a366004613fbf565b60996020525f908152604090205481565b348015610346575f80fd5b506102fd610355366004613fbf565b610f7e565b348015610365575f80fd5b5060335460ff166040519015158152602001610307565b348015610387575f80fd5b50610256610396366004613fda565b610fde565b3480156103a6575f80fd5b506102566103b5366004613fbf565b6110b9565b6102566103c83660046140a5565b61116b565b3480156103d8575f80fd5b506102fd60985481565b3480156103ed575f80fd5b506102566103fc3660046140ed565b6111fd565b34801561040c575f80fd5b5061042061041b366004613fda565b6113b3565b6040516001600160a01b039091168152602001610307565b348015610443575f80fd5b506102566113db565b348015610457575f80fd5b506102fd610466366004613fbf565b6114a8565b348015610476575f80fd5b50610256610485366004613fda565b6115dd565b348015610495575f80fd5b506102fd6104a436600461410d565b6116b8565b6102566104b736600461410d565b61180c565b3480156104c7575f80fd5b506104db6104d6366004613fbf565b611b2f565b604080519687526020870195909552938501929092526060840152608083015260a082015260c001610307565b348015610513575f80fd5b50610256610522366004614137565b611ff9565b348015610532575f80fd5b506102fd61054136600461410d565b6121c5565b348015610551575f80fd5b5061025661056036600461410d565b61236c565b348015610570575f80fd5b506102fd60975481565b348015610585575f80fd5b5061025661059436600461416c565b6125b8565b3480156105a4575f80fd5b506102566105b3366004613fbf565b612712565b3480156105c3575f80fd5b506105cc612967565b60405161030791906141d1565b3480156105e4575f80fd5b506102566105f3366004613fda565b6129c7565b348015610603575f80fd5b505f54610420906001600160a01b031681565b348015610621575f80fd5b506104db612bdd565b5f546040517f9be918e60000000000000000000000000000000000000000000000000000000081526001600160a01b03808416600483015283921690639be918e690602401602060405180830381865afa15801561068a573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106ae919061421d565b6106e4576040517f981a2a2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f54604051632474521560e21b81527faf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c60048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa15801561074f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610773919061421d565b6107a9576040517f210d9c6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527f305e5896d422923741b53f048a145a568046f2ae0bba25aa944a6839a26690ef60048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015610828573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061084c919061424c565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248301529192509084169063095ea7b3906044016020604051808303815f875af11580156108d4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108f8919061421d565b50505050565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa15801561094a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061096e919061421d565b6109a4576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609a548110156109e0576040517fe1a3dd9200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60978190556040518181527f44a9f72c31db7b99a131a49de95fe2420c60e9fe9bff0a1a13d47b4af14566b4906020015b60405180910390a150565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa158015610a68573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8c919061421d565b610ac2576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f546001600160a01b031615610b04576040517f18e6d51900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b0d81612f37565b5f80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117825560405190917f9cf19cefd9aab739c33b95716ee3f3f921f219dc6d7aae25e1f9497b3788915091a250565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa158015610bb8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bdc919061421d565b610c12576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609754609a54829190610c26908390614294565b1115610c5e576040517f9aca5e2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b81811015610da757610c97848483818110610c7d57610c7d6142a7565b9050602002016020810190610c929190613fbf565b612f37565b60995f858584818110610cac57610cac6142a7565b9050602002016020810190610cc19190613fbf565b6001600160a01b03166001600160a01b031681526020019081526020015f20545f03610d5a57609a848483818110610cfb57610cfb6142a7565b9050602002016020810190610d109190613fbf565b81546001810183555f928352602090922090910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039092169190911790555b600160995f868685818110610d7157610d716142a7565b9050602002016020810190610d869190613fbf565b6001600160a01b0316815260208101919091526040015f2055600101610c60565b507f7c2453850055cd8625ebfc0116c7b3eec5d5e6b0b584e69a719089e22f461d638383604051610dd99291906142d4565b60405180910390a1505050565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa158015610e32573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e56919061421d565b610e8c576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805f5b818110156108f857610ec6848483818110610eac57610eac6142a7565b9050602002016020810190610ec19190613fbf565b612f77565b600101610e8f565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa158015610f1a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f3e919061421d565b610f74576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f7c6130c7565b565b5f805f805f805f610f8e88611b2f565b95509550955095509550955080828486888a610faa9190614294565b610fb49190614294565b610fbe9190614294565b610fc89190614294565b610fd29190614294565b98975050505050505050565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa15801561102a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061104e919061421d565b611084576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609b8190556040518181527fae34faed95cd4022e6c7e9bb4219e7f69d343fcf210c8893cb520fa603e7d17790602001610a11565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa158015611105573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611129919061421d565b61115f576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61116881612f77565b50565b611173613137565b61117b613190565b5f61119b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee34866131e3565b90506111a6816132b0565b336001600160a01b03167f8b0422d41caf5eb583695377e98b5041a1d241a7c80483cf182b1311c48c93b7348386866040516111e59493929190614321565b60405180910390a2506111f86001606555565b505050565b611205613137565b5f54604051632474521560e21b81527faf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c60048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015611270573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611294919061421d565b6112ca576040517f210d9c6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f609a83815481106112de576112de6142a7565b5f918252602082200154604080517f5e68300700000000000000000000000000000000000000000000000000000000815290516001600160a01b0390921693508392635e683007928692600480820193929182900301818588803b158015611344575f80fd5b505af1158015611356573d5f803e3d5ffd5b5050604080516001600160a01b0386168152602081018790527fcec1f18c3ab8ddaaa107a1591e3c369667eec613626611a8deaedef43069fcdd945001915061139c9050565b60405180910390a1506113af6001606555565b5050565b609a81815481106113c2575f80fd5b5f918252602090912001546001600160a01b0316905081565b5f54604051632474521560e21b81527faf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c60048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015611446573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061146a919061421d565b6114a0576040517f210d9c6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f7c6133a5565b5f806114b383610f7e565b5f546040517f435756480000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152929350911690634357564890602401602060405180830381865afa158015611515573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611539919061437b565b81111561154857505f92915050565b5f546040517f435756480000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015283921690634357564890602401602060405180830381865afa1580156115a8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115cc919061437b565b6115d69190614392565b9392505050565b5f8054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa158015611629573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061164d919061421d565b611683576040517f164931f400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60988190556040518181527f1bba2f1175afe384c3b2efde45f19740b744459c61a7700994196fe4d84af17690602001610a11565b5f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527f0900d19e2faab4e79535bcc1cfdb63996d43c8e38d9a260cf2b01e820b5f84d4600482015282916001600160a01b03169063e16c7d9890602401602060405180830381865afa158015611737573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061175b919061424c565b6040517fb3596f070000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301529192508291670de0b6b3a7640000919083169063b3596f0790602401602060405180830381865afa1580156117c8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117ec919061437b565b6117f686836143a5565b61180091906143bc565b93505050505b92915050565b5f54604051632474521560e21b81527faf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c60048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015611877573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061189b919061421d565b6118d1576040517f210d9c6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f546040517f9be918e60000000000000000000000000000000000000000000000000000000081526001600160a01b03808516600483015284921690639be918e690602401602060405180830381865afa158015611931573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611955919061421d565b61198b576040517f981a2a2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b345f61199785836116b8565b905083811080611a2557506040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038716906370a0823190602401602060405180830381865afa1580156119ff573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a23919061437b565b105b15611a5c576040517f21d9b3bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018290526001600160a01b0386169063a9059cbb906044016020604051808303815f875af1158015611abf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ae3919061421d565b5060408051838152602081018390526001600160a01b038716917fdfcec2e5d46add579374c8b094c104992049258e32c4b148984940d21f023308910160405180910390a25050505050565b5f80546040517f9be918e60000000000000000000000000000000000000000000000000000000081526001600160a01b03808516600483015283928392839283928392899290911690639be918e690602401602060405180830381865afa158015611b9c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bc0919061421d565b611bf6576040517f981a2a2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03891601611c3f57611c2e612bdd565b965096509650965096509650611fef565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038916906370a0823190602401602060405180830381865afa158015611c9a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cbe919061437b565b609a549097505f5b81811015611e3957896001600160a01b03166370a08231609a8381548110611cf057611cf06142a7565b5f9182526020909120015460405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039091166004820152602401602060405180830381865afa158015611d55573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d79919061437b565b611d839089614294565b9750609a8181548110611d9857611d986142a7565b5f918252602090912001546040517f5373433f0000000000000000000000000000000000000000000000000000000081526001600160a01b038c8116600483015290911690635373433f90602401602060405180830381865afa158015611e01573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e25919061437b565b611e2f9088614294565b9650600101611cc6565b505f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527fe1defbdba228c2f450cc8f3382e0fb463dd4233b2b59c3d3ed9e518e77222ed360048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015611eb9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611edd919061424c565b6040517fc5bac6510000000000000000000000000000000000000000000000000000000081526001600160a01b038c811660048301529192509082169063c5bac65190602401602060405180830381865afa158015611f3e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f62919061437b565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301529197505f9650908b16906370a0823190602401602060405180830381865afa158015611fc6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fea919061437b565b935050505b5091939550919395565b612001613137565b5f54604051632474521560e21b81527faf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c60048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa15801561206c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612090919061421d565b6120c6576040517f210d9c6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f546040517f9be918e60000000000000000000000000000000000000000000000000000000081526001600160a01b03808516600483015284921690639be918e690602401602060405180830381865afa158015612126573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061214a919061421d565b612180576040517f981a2a2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f609a8581548110612194576121946142a7565b5f918252602090912001546001600160a01b0390811691506121b99085168285613400565b50506111f86001606555565b5f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527f0900d19e2faab4e79535bcc1cfdb63996d43c8e38d9a260cf2b01e820b5f84d4600482015282916001600160a01b03169063e16c7d9890602401602060405180830381865afa158015612244573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612268919061424c565b90505f819050806001600160a01b031663b4b464346040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122aa573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122ce919061437b565b6040517fb3596f070000000000000000000000000000000000000000000000000000000081526001600160a01b03878116600483015283169063b3596f0790602401602060405180830381865afa15801561232b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061234f919061437b565b61235990866143a5565b61236391906143bc565b95945050505050565b612374613137565b5f54604051632474521560e21b81527faf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c60048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa1580156123df573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612403919061421d565b612439576040517f210d9c6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f546040517f9be918e60000000000000000000000000000000000000000000000000000000081526001600160a01b03808516600483015284921690639be918e690602401602060405180830381865afa158015612499573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124bd919061421d565b6124f3576040517f981a2a2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527fe1defbdba228c2f450cc8f3382e0fb463dd4233b2b59c3d3ed9e518e77222ed360048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612572573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612596919061424c565b90506125ac6001600160a01b0385168285613400565b50506113af6001606555565b6125c0613137565b6125c8613190565b5f546040517f9be918e60000000000000000000000000000000000000000000000000000000081526001600160a01b03808816600483015287921690639be918e690602401602060405180830381865afa158015612628573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061264c919061421d565b612682576040517f981a2a2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61268e8787876131e3565b90506126a56001600160a01b0388163330896134c7565b6126ae816132b0565b866001600160a01b0316336001600160a01b03167f07c31fccf51996f0f4ea01c3a55191786b3a8cd89f696db4d42adaa99b0e15f1888488886040516126f79493929190614321565b60405180910390a3505061270b6001606555565b5050505050565b5f547501000000000000000000000000000000000000000000900460ff161580801561275b57505f5460017401000000000000000000000000000000000000000090910460ff16105b8061278c5750303b15801561278c57505f5474010000000000000000000000000000000000000000900460ff166001145b6128035760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b5f80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790558015612887575f80547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1675010000000000000000000000000000000000000000001790555b61289082612f37565b612898613518565b6128a06135b0565b600a6097555f80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038416908117825560405190917f9cf19cefd9aab739c33b95716ee3f3f921f219dc6d7aae25e1f9497b3788915091a280156113af575f80547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15050565b6060609a8054806020026020016040519081016040528092919081815260200182805480156129bd57602002820191905f5260205f20905b81546001600160a01b0316815260019091019060200180831161299f575b5050505050905090565b6129cf613137565b5f54604051632474521560e21b81527faf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c60048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015612a3a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a5e919061421d565b612a94576040517f210d9c6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527fe1defbdba228c2f450cc8f3382e0fb463dd4233b2b59c3d3ed9e518e77222ed360048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612b13573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b37919061424c565b9050806001600160a01b0316635f3cbfd4836040518263ffffffff1660e01b81526004015f604051808303818588803b158015612b72575f80fd5b505af1158015612b84573d5f803e3d5ffd5b5050604080516001600160a01b0386168152602081018790527fcec1f18c3ab8ddaaa107a1591e3c369667eec613626611a8deaedef43069fcdd9450019150612bca9050565b60405180910390a1506111686001606555565b609a5447905f908190819081908190815b81811015612cd957609a8181548110612c0957612c096142a7565b5f91825260209091200154612c28906001600160a01b03163188614294565b9650609a8181548110612c3d57612c3d6142a7565b5f9182526020918290200154604080517f497edda000000000000000000000000000000000000000000000000000000000815290516001600160a01b039092169263497edda0926004808401938290030181865afa158015612ca1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cc5919061437b565b612ccf9087614294565b9550600101612bee565b505f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527fe1defbdba228c2f450cc8f3382e0fb463dd4233b2b59c3d3ed9e518e77222ed360048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612d59573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d7d919061424c565b6040517fc5bac65100000000000000000000000000000000000000000000000000000000815273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60048201529091506001600160a01b0382169063c5bac65190602401602060405180830381865afa158015612def573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e13919061437b565b5f80546040517fe16c7d980000000000000000000000000000000000000000000000000000000081527f305e5896d422923741b53f048a145a568046f2ae0bba25aa944a6839a26690ef600482015292975090916001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015612e97573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ebb919061424c565b9050806001600160a01b0316636a4c410d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ef9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f1d919061437b565b9450816001600160a01b0316319350505050909192939495565b6001600160a01b038116611168576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f612f8182613648565b9050612f8c826136ce565b612f9582613782565b6001600160a01b0382165f90815260996020526040812055609a8054612fbd90600190614392565b81548110612fcd57612fcd6142a7565b5f91825260209091200154609a80546001600160a01b039092169183908110612ff857612ff86142a7565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550609a805480613034576130346143f4565b5f8281526020908190207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff908301810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690559091019091556040516001600160a01b03841681527fb17adb7f863ad4dced68bd4045e81e087cb8c5b536bf2dbda6c8176e5fc593b9910161295b565b6130cf613a28565b603380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6002606554036131895760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016127fa565b6002606555565b60335460ff1615610f7c5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016127fa565b5f8215806131f2575060985483105b15613229576040517f91c6ba0200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6132338484613a7a565b1561326a576040517f1751ef8300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61327484846121c5565b9050818110156115d6576040517f1ec9a89400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f9054906101000a90046001600160a01b03166001600160a01b031662b83bce6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156132ff573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613323919061424c565b6040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820152602481018490529091506001600160a01b038216906340c10f19906044015f604051808303815f87803b158015613384575f80fd5b505af1158015613396573d5f803e3d5ffd5b505050505050565b6001606555565b6133ad613190565b603380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861311a3390565b6040516001600160a01b0383166024820152604481018290526111f89084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613bda565b6040516001600160a01b03808516602483015283166044820152606481018290526108f89085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401613445565b5f547501000000000000000000000000000000000000000000900460ff166135a85760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016127fa565b610f7c613cc0565b5f547501000000000000000000000000000000000000000000900460ff166136405760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016127fa565b610f7c613d7a565b609a545f90815b8181101561369c57836001600160a01b0316609a8281548110613674576136746142a7565b5f918252602090912001546001600160a01b031603613694579392505050565b60010161364f565b6040517fa5cddd8f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f816001600160a01b031631826001600160a01b031663497edda06040518163ffffffff1660e01b8152600401602060405180830381865afa158015613716573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061373a919061437b565b6137449190614294565b9050609b548111156113af576040517f706a3d5300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f9054906101000a90046001600160a01b03166001600160a01b031663770672a66040518163ffffffff1660e01b81526004015f60405180830381865afa1580156137d1573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052613816919081019061444e565b80519091505f805b8281101561270b5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b0316848281518110613856576138566142a7565b60200260200101516001600160a01b03160315613a1857846001600160a01b0316635373433f85838151811061388e5761388e6142a7565b60200260200101516040518263ffffffff1660e01b81526004016138c191906001600160a01b0391909116815260200190565b602060405180830381865afa1580156138dc573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613900919061437b565b848281518110613912576139126142a7565b60209081029190910101516040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152909116906370a0823190602401602060405180830381865afa15801561397b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061399f919061437b565b6139a99190614294565b9150609b54821115613a18578381815181106139c7576139c76142a7565b6020026020010151826040517fef008f080000000000000000000000000000000000000000000000000000000081526004016127fa9291906001600160a01b03929092168252602082015260400190565b613a2181614520565b905061381e565b60335460ff16610f7c5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016127fa565b5f80613a8584610f7e565b90507fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03851601613b43575f546040517f435756480000000000000000000000000000000000000000000000000000000081526001600160a01b03868116600483015290911690634357564890602401602060405180830381865afa158015613b17573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b3b919061437b565b109050611806565b5f546040517f435756480000000000000000000000000000000000000000000000000000000081526001600160a01b03868116600483015290911690634357564890602401602060405180830381865afa158015613ba3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613bc7919061437b565b613bd18483614294565b11949350505050565b5f613c2e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613e0a9092919063ffffffff16565b905080515f1480613c4e575080806020019051810190613c4e919061421d565b6111f85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016127fa565b5f547501000000000000000000000000000000000000000000900460ff16613d505760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016127fa565b603380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b5f547501000000000000000000000000000000000000000000900460ff1661339e5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016127fa565b6060613e1884845f85613e20565b949350505050565b606082471015613e985760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016127fa565b5f80866001600160a01b03168587604051613eb39190614579565b5f6040518083038185875af1925050503d805f8114613eed576040519150601f19603f3d011682016040523d82523d5f602084013e613ef2565b606091505b5091509150613f0387838387613f0e565b979650505050505050565b60608315613f7c5782515f03613f75576001600160a01b0385163b613f755760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016127fa565b5081613e18565b613e188383815115613f915781518083602001fd5b8060405162461bcd60e51b81526004016127fa9190614594565b6001600160a01b0381168114611168575f80fd5b5f60208284031215613fcf575f80fd5b81356115d681613fab565b5f60208284031215613fea575f80fd5b5035919050565b5f8060208385031215614002575f80fd5b823567ffffffffffffffff80821115614019575f80fd5b818501915085601f83011261402c575f80fd5b81358181111561403a575f80fd5b8660208260051b850101111561404e575f80fd5b60209290920196919550909350505050565b5f8083601f840112614070575f80fd5b50813567ffffffffffffffff811115614087575f80fd5b60208301915083602082850101111561409e575f80fd5b9250929050565b5f805f604084860312156140b7575f80fd5b83359250602084013567ffffffffffffffff8111156140d4575f80fd5b6140e086828701614060565b9497909650939450505050565b5f80604083850312156140fe575f80fd5b50508035926020909101359150565b5f806040838503121561411e575f80fd5b823561412981613fab565b946020939093013593505050565b5f805f60608486031215614149575f80fd5b83359250602084013561415b81613fab565b929592945050506040919091013590565b5f805f805f60808688031215614180575f80fd5b853561418b81613fab565b94506020860135935060408601359250606086013567ffffffffffffffff8111156141b4575f80fd5b6141c088828901614060565b969995985093965092949392505050565b602080825282518282018190525f9190848201906040850190845b818110156142115783516001600160a01b0316835292840192918401916001016141ec565b50909695505050505050565b5f6020828403121561422d575f80fd5b815180151581146115d6575f80fd5b805161424781613fab565b919050565b5f6020828403121561425c575f80fd5b81516115d681613fab565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561180657611806614267565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60208082528181018390525f908460408401835b868110156143165782356142fb81613fab565b6001600160a01b0316825291830191908301906001016142e8565b509695505050505050565b84815283602082015260606040820152816060820152818360808301375f818301608090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01601019392505050565b5f6020828403121561438b575f80fd5b5051919050565b8181038181111561180657611806614267565b808202811582820484141761180657611806614267565b5f826143ef577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f602080838503121561445f575f80fd5b825167ffffffffffffffff80821115614476575f80fd5b818501915085601f830112614489575f80fd5b81518181111561449b5761449b614421565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811085821117156144de576144de614421565b6040529182528482019250838101850191888311156144fb575f80fd5b938501935b82851015610fd2576145118561423c565b84529385019392850192614500565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361455057614550614267565b5060010190565b5f5b83811015614571578181015183820152602001614559565b50505f910152565b5f825161458a818460208701614557565b9190910192915050565b602081525f82518060208401526145b2816040850160208701614557565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea264697066735822122029c5c73aaf03e1de577c6c72cdc480afd19aeff8d5b00d7ad850c6c554036b5c64736f6c63430008150033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 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.