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 | 19730868 | 126 days ago | IN | 0 ETH | 0.01746244 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
LRTConverter
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import { LRTConstants } from "./utils/LRTConstants.sol"; import { LRTConfigRoleChecker, ILRTConfig, IAccessControl } from "./utils/LRTConfigRoleChecker.sol"; import { UtilLib } from "./utils/UtilLib.sol"; import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol"; import { IStrategy } from "./interfaces/IStrategy.sol"; import { ILRTOracle } from "./interfaces/ILRTOracle.sol"; import { IRSETH } from "./interfaces/IRSETH.sol"; import { IEigenDelegationManager } from "./interfaces/IEigenDelegationManager.sol"; import { ILRTConverter } from "./interfaces/ILRTConverter.sol"; import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { UnstakeStETH } from "./unstaking-adapters/UnstakeStETH.sol"; import { UnstakeSwETH } from "./unstaking-adapters/UnstakeSwETH.sol"; /// @title LRTConverter - Converts eigenlayer deployed LSTs to rsETH /// @notice Handles eigenlayer deposited LSTs to rsETH conversion contract LRTConverter is ILRTConverter, LRTConfigRoleChecker, ReentrancyGuardUpgradeable, UnstakeSwETH, UnstakeStETH, IERC721Receiver { using SafeERC20 for IERC20; mapping(bytes32 => bool) public processedWithdrawalRoots; mapping(address => bool) public convertableAssets; mapping(address => uint256) public conversionLimit; //needs to be added to total assets in protocol uint256 public ethValueInWithdrawal; /// @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); __ReentrancyGuard_init(); lrtConfig = ILRTConfig(lrtConfigAddr); emit UpdatedLRTConfig(lrtConfigAddr); } /// @dev Initializes the contract /// @param _withdrawalQueueAddress Address of withdrawal queue (stETH) /// @param _stETHAddress Address of stETH /// @param _swEXITAddress Address of swEXIT (swETH) /// @param _swETHAddress Address of swETH function initialize2( address _withdrawalQueueAddress, address _stETHAddress, address _swEXITAddress, address _swETHAddress ) external reinitializer(2) onlyLRTAdmin { __ReentrancyGuard_init(); __initializeSwETH(_swEXITAddress, _swETHAddress); __initializeStETH(_withdrawalQueueAddress, _stETHAddress); } modifier onlyConvertableAsset(address asset) { require(convertableAssets[asset], "Asset not supported"); _; } /// @notice Add convertable asset /// @param asset Asset address function addConvertableAsset(address asset) external onlyLRTManager { convertableAssets[asset] = true; } /// @notice Remove convertable asset /// @param asset Asset address function removeConvertableAsset(address asset) external onlyLRTManager { convertableAssets[asset] = false; } /// @notice Set conversion limit for asset /// @param asset Asset address /// @param limit Conversion limit function setConversionLimit(address asset, uint256 limit) external onlyLRTManager { conversionLimit[asset] = limit; } /// @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 returns (uint256 rsethAmountToMint) { ILRTDepositPool lrtDepositPool = ILRTDepositPool(lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL)); rsethAmountToMint = lrtDepositPool.getRsETHAmountToMint(asset, amount); } /// @notice swap ETH for LST asset which is accepted by LRTConverter and send to LRTDepositPool /// @dev use LRTOracle to get price for asset. Only callable by LRT manager /// @param asset Asset address to swap to /// @param minimumExpectedReturnAmount Minimum asset amount to swap to function swapEthToAsset( address asset, uint256 minimumExpectedReturnAmount ) external payable onlyLRTOperator onlyConvertableAsset(asset) returns (uint256 returnAmount) { ILRTDepositPool lrtDepositPool = ILRTDepositPool(lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL)); uint256 ethAmountSent = msg.value; returnAmount = lrtDepositPool.getSwapETHToAssetReturnAmount(asset, ethAmountSent); if (returnAmount < minimumExpectedReturnAmount || IERC20(asset).balanceOf(address(this)) < returnAmount) { revert NotEnoughAssetToTransfer(); } // account for limits and the asset value in contract conversionLimit[asset] += returnAmount; sendEthToDepositPool(ethAmountSent); IERC20(asset).safeTransfer(msg.sender, returnAmount); emit ETHSwappedForLST(ethAmountSent, asset, returnAmount); } function unstakeStEth(uint256 amountToUnstake) external onlyLRTOperator { _unstakeStEth(amountToUnstake); } function claimStEth(uint256 _requestId, uint256 _hint) external onlyLRTOperator { _claimStEth(_requestId, _hint); sendEthToDepositPool(address(this).balance); } function unstakeSwEth(uint256 amountToUnstake) external onlyLRTOperator { _unstakeSwEth(amountToUnstake); } function claimSwEth(uint256 _tokenId) external onlyLRTOperator { _claimSwEth(_tokenId); sendEthToDepositPool(address(this).balance); } /// @notice send asset from deposit pool to LRTConverter /// @dev Only callable by LRT manager and asset need to be approved /// @param _asset Asset address to send /// @param _amount Asset amount to send function transferAssetFromDepositPool( address _asset, uint256 _amount ) public onlyConvertableAsset(_asset) onlyLRTManager { address lrtDepositPoolAddress = lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL); address lrtOracleAddress = lrtConfig.getContract(LRTConstants.LRT_ORACLE); ILRTOracle lrtOracle = ILRTOracle(lrtOracleAddress); ethValueInWithdrawal += (_amount * lrtOracle.getAssetPrice(_asset)) / 1e18; IERC20(_asset).safeTransferFrom(lrtDepositPoolAddress, address(this), _amount); } function sendEthToDepositPool(uint256 _amount) internal { address lrtDepositPoolAddress = lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL); if (ethValueInWithdrawal > _amount) { ethValueInWithdrawal -= _amount; } else { ethValueInWithdrawal = 0; } // Send eth to deposit pool (bool success,) = payable(lrtDepositPoolAddress).call{ value: _amount }(""); if (!success) revert TokenTransferFailed(); emit EthTransferred(lrtDepositPoolAddress, _amount); } function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) { return this.onERC721Received.selector; } /// @dev fallback to receive funds receive() external payable { } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; 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 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: 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: BUSL-1.1 pragma solidity 0.8.21; import { IEigenDelegationManager } from "./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: 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(); //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 ETHSwappedForLST(uint256 ethAmount, address indexed toAsset, uint256 returnAmount); event EthTransferred(address to, uint256 amount); 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); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; interface ILRTOracle { // events event AssetPriceOracleUpdate(address indexed asset, address indexed priceOracle); // 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 { 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.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 { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; interface ILidoWithdrawalQueue { function requestWithdrawals( uint256[] calldata _amounts, address _owner ) external returns (uint256[] memory requestIds); /// Usage: findCheckpointHints(_requestIds, 1, getLastCheckpointIndex()) function findCheckpointHints( uint256[] calldata _requestIds, uint256 _firstIndex, uint256 _lastIndex ) external view returns (uint256[] memory hintIds); function getLastCheckpointIndex() external view returns (uint256); function claimWithdrawalsTo( uint256[] calldata _requestIds, uint256[] calldata _hints, address _recipient ) external; function finalize(uint256 _lastRequestIdToBeFinalized, uint256 _maxShareRate) external payable; function getLastRequestId() external view returns (uint256); } abstract contract UnstakeStETH is Initializable { ILidoWithdrawalQueue public withdrawalQueue; IERC20 public stETH; event UnstakeStETHStarted(uint256 tokenId); function __initializeStETH(address _withdrawalQueue, address _stETHAddress) internal onlyInitializing { withdrawalQueue = ILidoWithdrawalQueue(_withdrawalQueue); stETH = IERC20(_stETHAddress); } function _unstakeStEth(uint256 amountToUnstake) internal { stETH.approve(address(withdrawalQueue), amountToUnstake); uint256[] memory amounts = new uint256[](1); amounts[0] = amountToUnstake; uint256[] memory requestIds = withdrawalQueue.requestWithdrawals(amounts, address(this)); emit UnstakeStETHStarted(requestIds[0]); } function _claimStEth(uint256 _requestId, uint256 _hint) internal { uint256[] memory requestIds = new uint256[](1); uint256[] memory hints = new uint256[](1); requestIds[0] = _requestId; hints[0] = _hint; withdrawalQueue.claimWithdrawalsTo(requestIds, hints, address(this)); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; interface IswEXIT { function getLastTokenIdCreated() external view returns (uint256); function createWithdrawRequest(uint256 amount) external; function finalizeWithdrawal(uint256 tokenId) external; function processWithdrawals(uint256 lastTokenIdToProcess) external; } abstract contract UnstakeSwETH is Initializable { IswEXIT public swEXIT; IERC20 public swETH; event UnstakeSwETHStarted(uint256 tokenId); function __initializeSwETH(address _swEXITAddress, address _swETHAddress) internal onlyInitializing { swEXIT = IswEXIT(_swEXITAddress); swETH = IERC20(_swETHAddress); } function _unstakeSwEth(uint256 amountToUnstake) internal returns (uint256 tokenId) { swETH.approve(address(swEXIT), amountToUnstake); // Create withdrawal request swEXIT.createWithdrawRequest(amountToUnstake); tokenId = swEXIT.getLastTokenIdCreated(); emit UnstakeSwETHStarted(tokenId); } function _claimSwEth(uint256 _tokenId) internal { swEXIT.finalizeWithdrawal(_tokenId); } }
// 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; 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"); //nativeETH this is used to represent ETH bytes32 public constant NATIVE_ETH = keccak256("NATIVE_ETH"); 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"); }
// 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(); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CallerNotLRTConfigAdmin","type":"error"},{"inputs":[],"name":"CallerNotLRTConfigManager","type":"error"},{"inputs":[],"name":"CallerNotLRTConfigOperator","type":"error"},{"inputs":[],"name":"ConversionLimitReached","type":"error"},{"inputs":[],"name":"InvalidWithdrawer","type":"error"},{"inputs":[],"name":"MinimumExpectedReturnNotReached","type":"error"},{"inputs":[],"name":"NotEnoughAssetToTransfer","type":"error"},{"inputs":[],"name":"TokenTransferFailed","type":"error"},{"inputs":[],"name":"ValueAlreadyInUse","type":"error"},{"inputs":[],"name":"WithdrawalRootAlreadyProcess","type":"error"},{"inputs":[],"name":"WithdrawalRootNotPending","type":"error"},{"inputs":[],"name":"WithdrawalRootNotProcessed","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"reciever","type":"address"},{"indexed":false,"internalType":"uint256","name":"rsethAmount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"withdrawalRoot","type":"bytes32"}],"name":"ConvertedEigenlayerAssetToRsEth","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":"tokenId","type":"uint256"}],"name":"UnstakeStETHStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"UnstakeSwETHStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"lrtConfig","type":"address"}],"name":"UpdatedLRTConfig","type":"event"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"addConvertableAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"claimStEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"claimSwEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"conversionLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"convertableAssets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ethValueInWithdrawal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"lrtConfigAddr","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_withdrawalQueueAddress","type":"address"},{"internalType":"address","name":"_stETHAddress","type":"address"},{"internalType":"address","name":"_swEXITAddress","type":"address"},{"internalType":"address","name":"_swETHAddress","type":"address"}],"name":"initialize2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lrtConfig","outputs":[{"internalType":"contract ILRTConfig","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"processedWithdrawalRoots","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"removeConvertableAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"setConversionLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stETH","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swETH","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swEXIT","outputs":[{"internalType":"contract IswEXIT","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"minimumExpectedReturnAmount","type":"uint256"}],"name":"swapEthToAsset","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferAssetFromDepositPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountToUnstake","type":"uint256"}],"name":"unstakeStEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountToUnstake","type":"uint256"}],"name":"unstakeSwEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lrtConfigAddr","type":"address"}],"name":"updateLRTConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalQueue","outputs":[{"internalType":"contract ILidoWithdrawalQueue","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405234801561001057600080fd5b5061001961001e565b6100ea565b600054600160a81b900460ff161561008c5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b600054600160a01b900460ff908116146100e8576000805460ff60a01b191660ff60a01b17905560405160ff81527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61235580620000fa6000396000f3fe6080604052600436106101445760003560e01c8063585f2337116100b6578063c1fe3e481161006f578063c1fe3e48146103db578063c4d66de8146103fb578063d3b063081461041b578063e1bce57a14610448578063f1650a4614610468578063f3cbc0f51461048857600080fd5b8063585f2337146103145780635e7a000f14610335578063619fba78146103555780636a4c410d14610385578063a881cda21461039b578063ba5bb442146103bb57600080fd5b806323f87d011161010857806323f87d011461023457806324ef3a0b146102545780632f0d3d831461027457806337d5fe99146102945780633d16293a146102b4578063567c7f07146102f457600080fd5b806305a77dc9146101505780630dd4433d14610172578063150b7a021461019257806315864e0a146101dc57806318a66953146101fc57600080fd5b3661014b57005b600080fd5b34801561015c57600080fd5b5061017061016b366004611dcd565b6104a8565b005b34801561017e57600080fd5b5061017061018d366004611df1565b610566565b34801561019e57600080fd5b506101be6101ad366004611e0a565b630a85bd0160e11b95945050505050565b6040516001600160e01b031990911681526020015b60405180910390f35b3480156101e857600080fd5b506101706101f7366004611dcd565b610618565b34801561020857600080fd5b5060345461021c906001600160a01b031681565b6040516001600160a01b0390911681526020016101d3565b34801561024057600080fd5b5061017061024f366004611df1565b610723565b34801561026057600080fd5b5061017061026f366004611dcd565b6107c9565b34801561028057600080fd5b5061017061028f366004611ea9565b61088a565b3480156102a057600080fd5b5060355461021c906001600160a01b031681565b3480156102c057600080fd5b506102e46102cf366004611dcd565b60386020526000908152604090205460ff1681565b60405190151581526020016101d3565b34801561030057600080fd5b5061017061030f366004611ecb565b61093e565b610327610322366004611ecb565b6109f7565b6040519081526020016101d3565b34801561034157600080fd5b50610170610350366004611df1565b610d17565b34801561036157600080fd5b506102e4610370366004611df1565b60376020526000908152604090205460ff1681565b34801561039157600080fd5b50610327603a5481565b3480156103a757600080fd5b506101706103b6366004611ecb565b610dbd565b3480156103c757600080fd5b506103276103d6366004611ecb565b611089565b3480156103e757600080fd5b5060365461021c906001600160a01b031681565b34801561040757600080fd5b50610170610416366004611dcd565b611181565b34801561042757600080fd5b50610327610436366004611dcd565b60396020526000908152604090205481565b34801561045457600080fd5b5060335461021c906001600160a01b031681565b34801561047457600080fd5b5060005461021c906001600160a01b031681565b34801561049457600080fd5b506101706104a3366004611ef7565b6112b4565b600054604051632474521560e21b81526000805160206122c083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015610504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105289190611f53565b61054557604051631086ce3360e11b815260040160405180910390fd5b6001600160a01b03166000908152603860205260409020805460ff19169055565b600054604051632474521560e21b815260008051602061230083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa1580156105c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e69190611f53565b61060357604051632e8726f760e11b815260040160405180910390fd5b61060c81611416565b61061547611477565b50565b60008054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa158015610667573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068b9190611f53565b6106a8576040516305924c7d60e21b815260040160405180910390fd5b6000546001600160a01b0316156106d2576040516318e6d51960e01b815260040160405180910390fd5b6106db816115dd565b600080546001600160a01b0319166001600160a01b038316908117825560405190917f9cf19cefd9aab739c33b95716ee3f3f921f219dc6d7aae25e1f9497b3788915091a250565b600054604051632474521560e21b815260008051602061230083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa15801561077f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a39190611f53565b6107c057604051632e8726f760e11b815260040160405180910390fd5b61061581611604565b600054604051632474521560e21b81526000805160206122c083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015610825573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108499190611f53565b61086657604051631086ce3360e11b815260040160405180910390fd5b6001600160a01b03166000908152603860205260409020805460ff19166001179055565b600054604051632474521560e21b815260008051602061230083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa1580156108e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090a9190611f53565b61092757604051632e8726f760e11b815260040160405180910390fd5b6109318282611786565b61093a47611477565b5050565b600054604051632474521560e21b81526000805160206122c083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa15801561099a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109be9190611f53565b6109db57604051631086ce3360e11b815260040160405180910390fd5b6001600160a01b03909116600090815260396020526040902055565b60008054604051632474521560e21b815260008051602061230083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015610a54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a789190611f53565b610a9557604051632e8726f760e11b815260040160405180910390fd5b6001600160a01b038316600090815260386020526040902054839060ff16610afa5760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064015b60405180910390fd5b60008054604051631c2d8fb360e31b81526000805160206122e083398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015610b51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b759190611f75565b604051630a3185ed60e41b81526001600160a01b038781166004830152346024830181905292935083169063a3185ed090604401602060405180830381865afa158015610bc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bea9190611f92565b935084841080610c6157506040516370a0823160e01b815230600482015284906001600160a01b038816906370a0823190602401602060405180830381865afa158015610c3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c5f9190611f92565b105b15610c7f576040516321d9b3bb60e01b815260040160405180910390fd5b6001600160a01b03861660009081526039602052604081208054869290610ca7908490611fc1565b90915550610cb6905081611477565b610cca6001600160a01b0387163386611876565b60408051828152602081018690526001600160a01b038816917fdfcec2e5d46add579374c8b094c104992049258e32c4b148984940d21f023308910160405180910390a250505092915050565b600054604051632474521560e21b815260008051602061230083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015610d73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d979190611f53565b610db457604051632e8726f760e11b815260040160405180910390fd5b61093a816118de565b6001600160a01b038216600090815260386020526040902054829060ff16610e1d5760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b6044820152606401610af1565b600054604051632474521560e21b81526000805160206122c083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015610e79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9d9190611f53565b610eba57604051631086ce3360e11b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81526000805160206122e083398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015610f11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f359190611f75565b60008054604051631c2d8fb360e31b81527f0900d19e2faab4e79535bcc1cfdb63996d43c8e38d9a260cf2b01e820b5f84d4600482015292935090916001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015610fa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc79190611f75565b60405163b3596f0760e01b81526001600160a01b0387811660048301529192508291670de0b6b3a7640000919083169063b3596f0790602401602060405180830381865afa15801561101d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110419190611f92565b61104b9087611fda565b6110559190611ff1565b603a60008282546110669190611fc1565b9091555061108190506001600160a01b038716843088611a72565b505050505050565b60008054604051631c2d8fb360e31b81526000805160206122e0833981519152600482015282916001600160a01b03169063e16c7d9890602401602060405180830381865afa1580156110e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111049190611f75565b604051635d2dda2160e11b81526001600160a01b038681166004830152602482018690529192509082169063ba5bb44290604401602060405180830381865afa158015611155573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111799190611f92565b949350505050565b600054600160a81b900460ff16158080156111a957506000546001600160a01b90910460ff16105b806111ca5750303b1580156111ca5750600054600160a01b900460ff166001145b6111e65760405162461bcd60e51b8152600401610af190612013565b6000805460ff60a01b1916600160a01b1790558015611213576000805460ff60a81b1916600160a81b1790555b61121c826115dd565b611224611ab0565b600080546001600160a01b0319166001600160a01b038416908117825560405190917f9cf19cefd9aab739c33b95716ee3f3f921f219dc6d7aae25e1f9497b3788915091a2801561093a576000805460ff60a81b19169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b600054600290600160a81b900460ff161580156112df575060005460ff808316600160a01b90920416105b6112fb5760405162461bcd60e51b8152600401610af190612013565b60008054600160a81b61ffff60a01b19909116600160a01b60ff85160260ff60a81b19161717808255604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa15801561136f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113939190611f53565b6113b0576040516305924c7d60e21b815260040160405180910390fd5b6113b8611ab0565b6113c28383611ae3565b6113cc8585611b3a565b6000805460ff60a81b1916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050565b603354604051635e15c74960e01b8152600481018390526001600160a01b0390911690635e15c74990602401600060405180830381600087803b15801561145c57600080fd5b505af1158015611470573d6000803e3d6000fd5b5050505050565b60008054604051631c2d8fb360e31b81526000805160206122e083398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa1580156114ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f29190611f75565b905081603a54111561151b5781603a60008282546115109190612061565b909155506115219050565b6000603a555b6000816001600160a01b03168360405160006040518083038185875af1925050503d806000811461156e576040519150601f19603f3d011682016040523d82523d6000602084013e611573565b606091505b50509050806115955760405163022e258160e11b815260040160405180910390fd5b604080516001600160a01b0384168152602081018590527fcec1f18c3ab8ddaaa107a1591e3c369667eec613626611a8deaedef43069fcdd91015b60405180910390a1505050565b6001600160a01b038116610615576040516342bcdf7f60e11b815260040160405180910390fd5b60365460355460405163095ea7b360e01b81526001600160a01b0391821660048201526024810184905291169063095ea7b3906044016020604051808303816000875af1158015611659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167d9190611f53565b506040805160018082528183019092526000916020808301908036833701905050905081816000815181106116b4576116b461208a565b6020908102919091010152603554604051636b34082160e11b81526000916001600160a01b03169063d6681042906116f290859030906004016120db565b6000604051808303816000875af1158015611711573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526117399190810190612105565b90507f8d29c3cc4ecd5557acf0513e125eccf06f4c6f9f5ec12c5baa5ba7eac2a9458e8160008151811061176f5761176f61208a565b60200260200101516040516115d091815260200190565b60408051600180825281830190925260009160208083019080368337505060408051600180825281830190925292935060009291506020808301908036833701905050905083826000815181106117df576117df61208a565b60200260200101818152505082816000815181106117ff576117ff61208a565b6020908102919091010152603554604051635e7eead960e01b81526001600160a01b0390911690635e7eead99061183e908590859030906004016121c3565b600060405180830381600087803b15801561185857600080fd5b505af115801561186c573d6000803e3d6000fd5b5050505050505050565b6040516001600160a01b0383166024820152604481018290526118d990849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611b91565b505050565b60345460335460405163095ea7b360e01b81526001600160a01b03918216600482015260248101849052600092919091169063095ea7b3906044016020604051808303816000875af1158015611938573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195c9190611f53565b50603354604051633a6e4e8d60e11b8152600481018490526001600160a01b03909116906374dc9d1a90602401600060405180830381600087803b1580156119a357600080fd5b505af11580156119b7573d6000803e3d6000fd5b50505050603360009054906101000a90046001600160a01b03166001600160a01b031663061a499f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a329190611f92565b90507f5d5fdc94abc691d6fb4e699a6aacafbc8c83a13bdfbd183a271e1d1f1c5ac02581604051611a6591815260200190565b60405180910390a1919050565b6040516001600160a01b0380851660248301528316604482015260648101829052611aaa9085906323b872dd60e01b906084016118a2565b50505050565b600054600160a81b900460ff16611ad95760405162461bcd60e51b8152600401610af190612201565b611ae1611c66565b565b600054600160a81b900460ff16611b0c5760405162461bcd60e51b8152600401610af190612201565b603380546001600160a01b039384166001600160a01b03199182161790915560348054929093169116179055565b600054600160a81b900460ff16611b635760405162461bcd60e51b8152600401610af190612201565b603580546001600160a01b039384166001600160a01b03199182161790915560368054929093169116179055565b6000611be6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611c959092919063ffffffff16565b9050805160001480611c07575080806020019051810190611c079190611f53565b6118d95760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610af1565b600054600160a81b900460ff16611c8f5760405162461bcd60e51b8152600401610af190612201565b60018055565b6060611179848460008585600080866001600160a01b03168587604051611cbc9190612270565b60006040518083038185875af1925050503d8060008114611cf9576040519150601f19603f3d011682016040523d82523d6000602084013e611cfe565b606091505b5091509150611d0f87838387611d1a565b979650505050505050565b60608315611d89578251600003611d82576001600160a01b0385163b611d825760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610af1565b5081611179565b6111798383815115611d9e5781518083602001fd5b8060405162461bcd60e51b8152600401610af1919061228c565b6001600160a01b038116811461061557600080fd5b600060208284031215611ddf57600080fd5b8135611dea81611db8565b9392505050565b600060208284031215611e0357600080fd5b5035919050565b600080600080600060808688031215611e2257600080fd5b8535611e2d81611db8565b94506020860135611e3d81611db8565b935060408601359250606086013567ffffffffffffffff80821115611e6157600080fd5b818801915088601f830112611e7557600080fd5b813581811115611e8457600080fd5b896020828501011115611e9657600080fd5b9699959850939650602001949392505050565b60008060408385031215611ebc57600080fd5b50508035926020909101359150565b60008060408385031215611ede57600080fd5b8235611ee981611db8565b946020939093013593505050565b60008060008060808587031215611f0d57600080fd5b8435611f1881611db8565b93506020850135611f2881611db8565b92506040850135611f3881611db8565b91506060850135611f4881611db8565b939692955090935050565b600060208284031215611f6557600080fd5b81518015158114611dea57600080fd5b600060208284031215611f8757600080fd5b8151611dea81611db8565b600060208284031215611fa457600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115611fd457611fd4611fab565b92915050565b8082028115828204841417611fd457611fd4611fab565b60008261200e57634e487b7160e01b600052601260045260246000fd5b500490565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b81810381811115611fd457611fd4611fab565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b838110156120d0578151875295820195908201906001016120b4565b509495945050505050565b6040815260006120ee60408301856120a0565b905060018060a01b03831660208301529392505050565b6000602080838503121561211857600080fd5b825167ffffffffffffffff8082111561213057600080fd5b818501915085601f83011261214457600080fd5b81518181111561215657612156612074565b8060051b604051601f19603f8301168101818110858211171561217b5761217b612074565b60405291825284820192508381018501918883111561219957600080fd5b938501935b828510156121b75784518452938501939285019261219e565b98975050505050505050565b6060815260006121d660608301866120a0565b82810360208401526121e881866120a0565b91505060018060a01b0383166040830152949350505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60005b8381101561226757818101518382015260200161224f565b50506000910152565b6000825161228281846020870161224c565b9190910192915050565b60208152600082518060208401526122ab81604085016020870161224c565b601f01601f1916919091016040019291505056feaf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c7a8fe1bac8d7638862c53b62ffada56d0a56c381287c35f66503b5b86fa88b8597667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929a264697066735822122073f26c48b3b92b96d2a7575a931b60be4e85e457a882caa86abd25139d14852164736f6c63430008150033
Deployed Bytecode
0x6080604052600436106101445760003560e01c8063585f2337116100b6578063c1fe3e481161006f578063c1fe3e48146103db578063c4d66de8146103fb578063d3b063081461041b578063e1bce57a14610448578063f1650a4614610468578063f3cbc0f51461048857600080fd5b8063585f2337146103145780635e7a000f14610335578063619fba78146103555780636a4c410d14610385578063a881cda21461039b578063ba5bb442146103bb57600080fd5b806323f87d011161010857806323f87d011461023457806324ef3a0b146102545780632f0d3d831461027457806337d5fe99146102945780633d16293a146102b4578063567c7f07146102f457600080fd5b806305a77dc9146101505780630dd4433d14610172578063150b7a021461019257806315864e0a146101dc57806318a66953146101fc57600080fd5b3661014b57005b600080fd5b34801561015c57600080fd5b5061017061016b366004611dcd565b6104a8565b005b34801561017e57600080fd5b5061017061018d366004611df1565b610566565b34801561019e57600080fd5b506101be6101ad366004611e0a565b630a85bd0160e11b95945050505050565b6040516001600160e01b031990911681526020015b60405180910390f35b3480156101e857600080fd5b506101706101f7366004611dcd565b610618565b34801561020857600080fd5b5060345461021c906001600160a01b031681565b6040516001600160a01b0390911681526020016101d3565b34801561024057600080fd5b5061017061024f366004611df1565b610723565b34801561026057600080fd5b5061017061026f366004611dcd565b6107c9565b34801561028057600080fd5b5061017061028f366004611ea9565b61088a565b3480156102a057600080fd5b5060355461021c906001600160a01b031681565b3480156102c057600080fd5b506102e46102cf366004611dcd565b60386020526000908152604090205460ff1681565b60405190151581526020016101d3565b34801561030057600080fd5b5061017061030f366004611ecb565b61093e565b610327610322366004611ecb565b6109f7565b6040519081526020016101d3565b34801561034157600080fd5b50610170610350366004611df1565b610d17565b34801561036157600080fd5b506102e4610370366004611df1565b60376020526000908152604090205460ff1681565b34801561039157600080fd5b50610327603a5481565b3480156103a757600080fd5b506101706103b6366004611ecb565b610dbd565b3480156103c757600080fd5b506103276103d6366004611ecb565b611089565b3480156103e757600080fd5b5060365461021c906001600160a01b031681565b34801561040757600080fd5b50610170610416366004611dcd565b611181565b34801561042757600080fd5b50610327610436366004611dcd565b60396020526000908152604090205481565b34801561045457600080fd5b5060335461021c906001600160a01b031681565b34801561047457600080fd5b5060005461021c906001600160a01b031681565b34801561049457600080fd5b506101706104a3366004611ef7565b6112b4565b600054604051632474521560e21b81526000805160206122c083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015610504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105289190611f53565b61054557604051631086ce3360e11b815260040160405180910390fd5b6001600160a01b03166000908152603860205260409020805460ff19169055565b600054604051632474521560e21b815260008051602061230083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa1580156105c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e69190611f53565b61060357604051632e8726f760e11b815260040160405180910390fd5b61060c81611416565b61061547611477565b50565b60008054604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa158015610667573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068b9190611f53565b6106a8576040516305924c7d60e21b815260040160405180910390fd5b6000546001600160a01b0316156106d2576040516318e6d51960e01b815260040160405180910390fd5b6106db816115dd565b600080546001600160a01b0319166001600160a01b038316908117825560405190917f9cf19cefd9aab739c33b95716ee3f3f921f219dc6d7aae25e1f9497b3788915091a250565b600054604051632474521560e21b815260008051602061230083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa15801561077f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a39190611f53565b6107c057604051632e8726f760e11b815260040160405180910390fd5b61061581611604565b600054604051632474521560e21b81526000805160206122c083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015610825573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108499190611f53565b61086657604051631086ce3360e11b815260040160405180910390fd5b6001600160a01b03166000908152603860205260409020805460ff19166001179055565b600054604051632474521560e21b815260008051602061230083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa1580156108e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090a9190611f53565b61092757604051632e8726f760e11b815260040160405180910390fd5b6109318282611786565b61093a47611477565b5050565b600054604051632474521560e21b81526000805160206122c083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa15801561099a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109be9190611f53565b6109db57604051631086ce3360e11b815260040160405180910390fd5b6001600160a01b03909116600090815260396020526040902055565b60008054604051632474521560e21b815260008051602061230083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015610a54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a789190611f53565b610a9557604051632e8726f760e11b815260040160405180910390fd5b6001600160a01b038316600090815260386020526040902054839060ff16610afa5760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b60448201526064015b60405180910390fd5b60008054604051631c2d8fb360e31b81526000805160206122e083398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015610b51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b759190611f75565b604051630a3185ed60e41b81526001600160a01b038781166004830152346024830181905292935083169063a3185ed090604401602060405180830381865afa158015610bc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bea9190611f92565b935084841080610c6157506040516370a0823160e01b815230600482015284906001600160a01b038816906370a0823190602401602060405180830381865afa158015610c3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c5f9190611f92565b105b15610c7f576040516321d9b3bb60e01b815260040160405180910390fd5b6001600160a01b03861660009081526039602052604081208054869290610ca7908490611fc1565b90915550610cb6905081611477565b610cca6001600160a01b0387163386611876565b60408051828152602081018690526001600160a01b038816917fdfcec2e5d46add579374c8b094c104992049258e32c4b148984940d21f023308910160405180910390a250505092915050565b600054604051632474521560e21b815260008051602061230083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015610d73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d979190611f53565b610db457604051632e8726f760e11b815260040160405180910390fd5b61093a816118de565b6001600160a01b038216600090815260386020526040902054829060ff16610e1d5760405162461bcd60e51b8152602060048201526013602482015272105cdcd95d081b9bdd081cdd5c1c1bdc9d1959606a1b6044820152606401610af1565b600054604051632474521560e21b81526000805160206122c083398151915260048201523360248201526001600160a01b03909116906391d1485490604401602060405180830381865afa158015610e79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9d9190611f53565b610eba57604051631086ce3360e11b815260040160405180910390fd5b60008054604051631c2d8fb360e31b81526000805160206122e083398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015610f11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f359190611f75565b60008054604051631c2d8fb360e31b81527f0900d19e2faab4e79535bcc1cfdb63996d43c8e38d9a260cf2b01e820b5f84d4600482015292935090916001600160a01b039091169063e16c7d9890602401602060405180830381865afa158015610fa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc79190611f75565b60405163b3596f0760e01b81526001600160a01b0387811660048301529192508291670de0b6b3a7640000919083169063b3596f0790602401602060405180830381865afa15801561101d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110419190611f92565b61104b9087611fda565b6110559190611ff1565b603a60008282546110669190611fc1565b9091555061108190506001600160a01b038716843088611a72565b505050505050565b60008054604051631c2d8fb360e31b81526000805160206122e0833981519152600482015282916001600160a01b03169063e16c7d9890602401602060405180830381865afa1580156110e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111049190611f75565b604051635d2dda2160e11b81526001600160a01b038681166004830152602482018690529192509082169063ba5bb44290604401602060405180830381865afa158015611155573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111799190611f92565b949350505050565b600054600160a81b900460ff16158080156111a957506000546001600160a01b90910460ff16105b806111ca5750303b1580156111ca5750600054600160a01b900460ff166001145b6111e65760405162461bcd60e51b8152600401610af190612013565b6000805460ff60a01b1916600160a01b1790558015611213576000805460ff60a81b1916600160a81b1790555b61121c826115dd565b611224611ab0565b600080546001600160a01b0319166001600160a01b038416908117825560405190917f9cf19cefd9aab739c33b95716ee3f3f921f219dc6d7aae25e1f9497b3788915091a2801561093a576000805460ff60a81b19169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b600054600290600160a81b900460ff161580156112df575060005460ff808316600160a01b90920416105b6112fb5760405162461bcd60e51b8152600401610af190612013565b60008054600160a81b61ffff60a01b19909116600160a01b60ff85160260ff60a81b19161717808255604051632474521560e21b815260048101929092523360248301526001600160a01b0316906391d1485490604401602060405180830381865afa15801561136f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113939190611f53565b6113b0576040516305924c7d60e21b815260040160405180910390fd5b6113b8611ab0565b6113c28383611ae3565b6113cc8585611b3a565b6000805460ff60a81b1916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050565b603354604051635e15c74960e01b8152600481018390526001600160a01b0390911690635e15c74990602401600060405180830381600087803b15801561145c57600080fd5b505af1158015611470573d6000803e3d6000fd5b5050505050565b60008054604051631c2d8fb360e31b81526000805160206122e083398151915260048201526001600160a01b039091169063e16c7d9890602401602060405180830381865afa1580156114ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f29190611f75565b905081603a54111561151b5781603a60008282546115109190612061565b909155506115219050565b6000603a555b6000816001600160a01b03168360405160006040518083038185875af1925050503d806000811461156e576040519150601f19603f3d011682016040523d82523d6000602084013e611573565b606091505b50509050806115955760405163022e258160e11b815260040160405180910390fd5b604080516001600160a01b0384168152602081018590527fcec1f18c3ab8ddaaa107a1591e3c369667eec613626611a8deaedef43069fcdd91015b60405180910390a1505050565b6001600160a01b038116610615576040516342bcdf7f60e11b815260040160405180910390fd5b60365460355460405163095ea7b360e01b81526001600160a01b0391821660048201526024810184905291169063095ea7b3906044016020604051808303816000875af1158015611659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167d9190611f53565b506040805160018082528183019092526000916020808301908036833701905050905081816000815181106116b4576116b461208a565b6020908102919091010152603554604051636b34082160e11b81526000916001600160a01b03169063d6681042906116f290859030906004016120db565b6000604051808303816000875af1158015611711573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526117399190810190612105565b90507f8d29c3cc4ecd5557acf0513e125eccf06f4c6f9f5ec12c5baa5ba7eac2a9458e8160008151811061176f5761176f61208a565b60200260200101516040516115d091815260200190565b60408051600180825281830190925260009160208083019080368337505060408051600180825281830190925292935060009291506020808301908036833701905050905083826000815181106117df576117df61208a565b60200260200101818152505082816000815181106117ff576117ff61208a565b6020908102919091010152603554604051635e7eead960e01b81526001600160a01b0390911690635e7eead99061183e908590859030906004016121c3565b600060405180830381600087803b15801561185857600080fd5b505af115801561186c573d6000803e3d6000fd5b5050505050505050565b6040516001600160a01b0383166024820152604481018290526118d990849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611b91565b505050565b60345460335460405163095ea7b360e01b81526001600160a01b03918216600482015260248101849052600092919091169063095ea7b3906044016020604051808303816000875af1158015611938573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195c9190611f53565b50603354604051633a6e4e8d60e11b8152600481018490526001600160a01b03909116906374dc9d1a90602401600060405180830381600087803b1580156119a357600080fd5b505af11580156119b7573d6000803e3d6000fd5b50505050603360009054906101000a90046001600160a01b03166001600160a01b031663061a499f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a329190611f92565b90507f5d5fdc94abc691d6fb4e699a6aacafbc8c83a13bdfbd183a271e1d1f1c5ac02581604051611a6591815260200190565b60405180910390a1919050565b6040516001600160a01b0380851660248301528316604482015260648101829052611aaa9085906323b872dd60e01b906084016118a2565b50505050565b600054600160a81b900460ff16611ad95760405162461bcd60e51b8152600401610af190612201565b611ae1611c66565b565b600054600160a81b900460ff16611b0c5760405162461bcd60e51b8152600401610af190612201565b603380546001600160a01b039384166001600160a01b03199182161790915560348054929093169116179055565b600054600160a81b900460ff16611b635760405162461bcd60e51b8152600401610af190612201565b603580546001600160a01b039384166001600160a01b03199182161790915560368054929093169116179055565b6000611be6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611c959092919063ffffffff16565b9050805160001480611c07575080806020019051810190611c079190611f53565b6118d95760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610af1565b600054600160a81b900460ff16611c8f5760405162461bcd60e51b8152600401610af190612201565b60018055565b6060611179848460008585600080866001600160a01b03168587604051611cbc9190612270565b60006040518083038185875af1925050503d8060008114611cf9576040519150601f19603f3d011682016040523d82523d6000602084013e611cfe565b606091505b5091509150611d0f87838387611d1a565b979650505050505050565b60608315611d89578251600003611d82576001600160a01b0385163b611d825760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610af1565b5081611179565b6111798383815115611d9e5781518083602001fd5b8060405162461bcd60e51b8152600401610af1919061228c565b6001600160a01b038116811461061557600080fd5b600060208284031215611ddf57600080fd5b8135611dea81611db8565b9392505050565b600060208284031215611e0357600080fd5b5035919050565b600080600080600060808688031215611e2257600080fd5b8535611e2d81611db8565b94506020860135611e3d81611db8565b935060408601359250606086013567ffffffffffffffff80821115611e6157600080fd5b818801915088601f830112611e7557600080fd5b813581811115611e8457600080fd5b896020828501011115611e9657600080fd5b9699959850939650602001949392505050565b60008060408385031215611ebc57600080fd5b50508035926020909101359150565b60008060408385031215611ede57600080fd5b8235611ee981611db8565b946020939093013593505050565b60008060008060808587031215611f0d57600080fd5b8435611f1881611db8565b93506020850135611f2881611db8565b92506040850135611f3881611db8565b91506060850135611f4881611db8565b939692955090935050565b600060208284031215611f6557600080fd5b81518015158114611dea57600080fd5b600060208284031215611f8757600080fd5b8151611dea81611db8565b600060208284031215611fa457600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115611fd457611fd4611fab565b92915050565b8082028115828204841417611fd457611fd4611fab565b60008261200e57634e487b7160e01b600052601260045260246000fd5b500490565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b81810381811115611fd457611fd4611fab565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b838110156120d0578151875295820195908201906001016120b4565b509495945050505050565b6040815260006120ee60408301856120a0565b905060018060a01b03831660208301529392505050565b6000602080838503121561211857600080fd5b825167ffffffffffffffff8082111561213057600080fd5b818501915085601f83011261214457600080fd5b81518181111561215657612156612074565b8060051b604051601f19603f8301168101818110858211171561217b5761217b612074565b60405291825284820192508381018501918883111561219957600080fd5b938501935b828510156121b75784518452938501939285019261219e565b98975050505050505050565b6060815260006121d660608301866120a0565b82810360208401526121e881866120a0565b91505060018060a01b0383166040830152949350505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60005b8381101561226757818101518382015260200161224f565b50506000910152565b6000825161228281846020870161224c565b9190910192915050565b60208152600082518060208401526122ab81604085016020870161224c565b601f01601f1916919091016040019291505056feaf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c7a8fe1bac8d7638862c53b62ffada56d0a56c381287c35f66503b5b86fa88b8597667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929a264697066735822122073f26c48b3b92b96d2a7575a931b60be4e85e457a882caa86abd25139d14852164736f6c63430008150033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.