Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
Staking
Compiler Version
v0.8.19+commit.7dd6d404
Contract Source Code (Solidity Standard Json-Input format)
/// SPDX-License-Identifier: MIT pragma solidity <0.9.0; import "@openzeppelin/[email protected]/access/OwnableUpgradeable.sol"; import "@openzeppelin/[email protected]/utils/Address.sol"; import "@openzeppelin/[email protected]/utils/math/Math.sol"; import "@openzeppelin/[email protected]/token/ERC20/utils/SafeERC20Upgradeable.sol"; import "@openzeppelin/[email protected]/proxy/utils/Initializable.sol"; interface IWBKN is IERC20Upgradeable { function release(address account, uint256 amount) external returns (bool); } /// @title Staking /// @custom:security-contact [email protected] contract Staking is OwnableUpgradeable { using Math for uint256; using Address for address; using SafeERC20Upgradeable for IERC20Upgradeable; using SafeERC20Upgradeable for IWBKN; /// The `user` is not WBKN holder error NotHolder(address user); /// The `user` has not allowed this contract to spend all WBKN Tokens error NotAllowedAllWBKN(address user); /// The period is not valid error InvalidPeriod(); /// BKN not released error NotReleased(); /// The `user` is already staking error AlreadyStaked(address user); /// The `user` is not staking error NotStaker(address user); /// The address is not a contract error NotContractAddress(); /// The address can't be the zero address error NotZeroAddress(); /// The variable can't have zero value error NotZeroValue(); /// The amount is not valid, exceed the max amount to lock error MaxToLockExceeded(address user, uint256 available); /// The round is paused error RoundPaused(); /// User provided an invalid round number to stake on error InvalidRoundNumber(); /// User is not able to unstake error UnableStake(); // Withdrawal windows // window 1: 2024-01-01 00:00:00 UTC to 2024-01-31 23:59:59 UTC uint64 private constant window1Start = 1704067200; uint64 private constant window1End = 1706745599; // window 2: 2024-07-01 00:00:00 UTC to 2024-07-31 23:59:59 UTC uint64 private constant window2Start = 1719792000; uint64 private constant window2End = 1722470399; // window 3: 2025-01-01 00:00:00 UTC to indefinite uint64 private constant window3Start = 1735689600; // 2023-01-01 00:00:00 UTC uint64 private constant stakingStart = 1672531200; // Instances of BKN and WBKN IERC20Upgradeable public BKNToken; IWBKN public WBKNToken; struct TransferUsers { uint8 from; // 1 for first round, 2 for second, 3 for third uint8 to; // 2 for second round, 3 for third address[] users; // users to move } struct StakingRound { bool statusPaused; // Variable to pause the round bool unstakeUnlocked; // Variable to unlock the unstake uint256 amountToDistribute; // Fixed amount of BKN to distribute in this round uint256 totalLocked; // Amount of BKN locked in this round by depositors, this will increment with time uint256 maxToLock; // Max amount that can be locked in this round mapping(address => uint256) userLockedFunds; // How much each user has staked mapping(address => bool) userIsPresent; // Helper to identify users in each round uint256 whenItWillUnlock; // 12/18/24 months starting on Jan 1 2023 } /// @dev StakingRounds by stakingRound index mapping(uint256 => StakingRound) public stakingRounds; /// @dev Gap variable for future upgrades uint256[45] __gap; /// @dev Issuance Index ---> Address of investor ---> Investor struct // mapping(uint256 => mapping(address => StakingRound)) public stakingRounds; /** * @dev Event when a staking position is opened * @param user address of the WBKN holder * @param amount amount of BKN staked */ event StakingEvent(address indexed user, uint256 amount); /** * @dev Event when a staking position is closed * @param user address of the BKN holder * @param amount amount of BKN unstaked * @param round from which it has been unstaked */ event UnstakingEvent(address indexed user, uint256 amount, uint8 round); /** * @dev Event when a round is paused/unpaused * @param round either 1, 2 or 3 * @param status true/false for paused/unpaused */ event RoundPausedEvent(uint8 round, bool status); /** * @dev Event when a round unstaking is unlocked/locked * @param round either 1, 2 or 3 * @param status true/false for unlocked/locked */ event UnlockUnstakeEvent(uint8 round, bool status); // transfer users /** * @dev Event when a round unstaking is unlocked/locked * @param amount amount of users transferred */ event TransferUsersEvent(uint256 amount); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize(address _WBKN, address _BKN, address _owner) initializer() external { if (!_WBKN.isContract()) revert NotContractAddress(); if (!_BKN.isContract()) revert NotContractAddress(); WBKNToken = IWBKN(_WBKN); BKNToken = IERC20Upgradeable(_BKN); __Ownable_init_unchained(); __Context_init_unchained(); transferOwnership(_owner); // 2023-12-31 23:59:59 UTC stage 1 end Date stakingRounds[1].whenItWillUnlock = 1704063600; // 2024-06-30 23:59:59 UTC stage 2 end Date stakingRounds[2].whenItWillUnlock = 1717192800; // 2024-12-31 23:59:59 UTC stage 3 end Date stakingRounds[3].whenItWillUnlock = 1735686000; // Max To locked stakingRounds[1].maxToLock = 6e24; stakingRounds[2].maxToLock = 8e24; stakingRounds[3].maxToLock = 11e24; // Amount to distribute stakingRounds[1].amountToDistribute = 6e23; stakingRounds[2].amountToDistribute = 10e23; stakingRounds[3].amountToDistribute = 14e23; } /** * @dev Receive fallback payable method. Don't accept ETH. */ receive() external payable { assert(false); } /** * @dev Reverts if a given address is equal to address(0) * @param to the address to check */ modifier validAddress(address to) { if (to == address(0)) revert NotZeroAddress(); /* solcov ignore next */ _; } // External functions /** * @dev Method to pause or unpause the staking round */ function pauseRound(uint8 round, bool status) external onlyOwner { ( StakingRound storage correctRound, bool itExists ) = _getStakingRoundById(round); if(!itExists) revert InvalidRoundNumber(); correctRound.statusPaused = status; emit RoundPausedEvent(round, status); } /** * @dev Method to withdraw any ERC20 from the contract * @param token address of the ERC20 token * @param amount amount of ERC20 token to withdraw< */ function withdrawERC20( IERC20Upgradeable token, uint256 amount, address to ) external validAddress(to) onlyOwner { if (amount == 0) revert NotZeroValue(); if (!address(token).isContract()) revert NotContractAddress(); token.safeTransfer(to, amount); // This already emits an event, not emitting redundant one here } /** * @dev Method to unlock the unstaking feature of each round. * @param round number of the round * @param status true or false to unlock/lock the staking round unstake */ function unlockStaking(uint8 round, bool status) external onlyOwner { ( StakingRound storage correctRound, bool itExists ) = _getStakingRoundById(round); if (!itExists) revert InvalidRoundNumber(); correctRound.unstakeUnlocked = status; emit UnlockUnstakeEvent(round, status); } /** * @dev Method for transfer user from one round to another * @param transfer struct with the data to transfer */ function transferUsers(TransferUsers memory transfer) external onlyOwner { //Remove each transfer.users from "from" staking round and add it to "to" staking round for (uint256 i = 0; i < transfer.users.length; i++) { address user = transfer.users[i]; uint256 amount = getDepositedAmount(user); if (amount == 0) revert NotZeroValue(); // Can't move from the last round // Can't transfer to the same round or a previous round if (transfer.from == 3 || transfer.to <= transfer.from) revert InvalidRoundNumber(); // _getStakingRoundById will return false for every value except for 1,2 and 3 ( StakingRound storage fromRound, bool itExists ) = _getStakingRoundById(transfer.from); ( StakingRound storage toRound, bool itAlsoExists ) = _getStakingRoundById(transfer.to); if (!itExists || !itAlsoExists) revert InvalidRoundNumber(); fromRound.userLockedFunds[user] = 0; fromRound.totalLocked -= amount; fromRound.userIsPresent[user] = false; toRound.userLockedFunds[user] = amount; if ((toRound.totalLocked + amount) > toRound.maxToLock) revert MaxToLockExceeded( user, toRound.maxToLock - toRound.totalLocked ); toRound.totalLocked += amount; toRound.userIsPresent[user] = true; } emit TransferUsersEvent(transfer.users.length); } /** * @dev Method to allow user staking. Conditions: * - The timestamp must be in a valid staking period * - The round should not be paused * - The user should not be a staker already * - The user must have the WBKN token approved to be spended by this contract * - The amount should not exceed the maxToLock of the corresponding round */ function deposit(uint8 round) external { address caller = _msgSender(); // Validate if the user is in the staking period if (!isStakingPeriod()) revert InvalidPeriod(); ( StakingRound storage correctRound, bool itExists ) = _getStakingRoundById(round); if (!itExists) revert InvalidRoundNumber(); if (correctRound.statusPaused) revert RoundPaused(); // Validate if the user is a staker (bool isUserStaker, ) = isStaker(caller); if (isUserStaker) revert AlreadyStaked(caller); // Validate if the user is a holder of WBKN token uint256 amount = WBKNToken.balanceOf(caller); if (amount == 0) revert NotHolder(caller); // Validate if the User has the WBKN token approved to the right amount uint256 allowed = WBKNToken.allowance(caller, address(this)); if (allowed == 0) revert NotZeroValue(); if (amount > allowed) revert NotAllowedAllWBKN(caller); // Validate the max locked amount is raised in each round if ((correctRound.totalLocked + amount) > correctRound.maxToLock) amount = correctRound.maxToLock - correctRound.totalLocked; if (amount == 0) revert MaxToLockExceeded(caller, amount); // Transfer WBKN in the contract (user must approve first) WBKNToken.safeTransferFrom(caller, address(this), amount); bool success = WBKNToken.release(address(this), amount); if (!success) revert NotReleased(); correctRound.userLockedFunds[caller] = amount; correctRound.userIsPresent[caller] = true; correctRound.totalLocked += amount; emit StakingEvent(caller, amount); } /** * @dev Method to allow user unstaking. Conditions: * - The timestamp must be in a valid unstaking period * - The user should be a staker already * - The user should have a positive amount of locked funds * @param round number of the round */ function unlock(uint8 round) external { if (!isUnstakeable(round)) revert UnableStake(); address caller = _msgSender(); ( StakingRound storage correctRound, , bool itExists ) = _getStakingRoundByStaker(caller); // Validate if the user is a staker if (!itExists) revert NotStaker(caller); if ( !(block.timestamp >= correctRound.whenItWillUnlock) || !correctRound.unstakeUnlocked ) revert UnableStake(); // Validate amount of BKN to unstake for the caller uint256 amount = getProjectedAmount(caller); if (amount == 0) revert NotZeroValue(); correctRound.userLockedFunds[caller] = 0; correctRound.userIsPresent[caller] = false; // Transfer BKN to the user BKNToken.safeTransfer(caller, amount); emit UnstakingEvent(caller, amount, round); } // Public functions /** * @dev Method to get the deposited amount for any user in all round * @param user address of the user */ function getDepositedAmount(address user) public view returns (uint256) { ( StakingRound storage correctRound, , bool itExists ) = _getStakingRoundByStaker(user); if (!itExists) return 0; else return correctRound.userLockedFunds[user]; } /** * @dev Method to get true or false if getTimestamp() is into a valid staking period */ function isStakingPeriod() public view returns (bool result) { (result, ) = _getStakingPeriod(uint64(_getTimestamp())); } /** * @dev Method to get true or false if _getTimestamp() is into a valid withdraw window */ function isWithdrawPeriod() public view returns (bool result) { result = _isWithdrawPeriod(uint64(_getTimestamp())); } /** * @dev Method to verify if the user is a staker * @param user address of the user */ function isStaker( address user ) public view returns (bool isUserStaker, uint roundId) { (, uint rountId, bool itExists) = _getStakingRoundByStaker(user); if (!itExists) return (false, rountId); return (true, rountId); } /** * @dev Method to verify if the user can or can't unstake BKN tokens * @param round number of the round */ function isUnstakeable(uint8 round) public view returns (bool) { ( StakingRound storage correctRound, bool itExists ) = _getStakingRoundById(round); if (!itExists) revert InvalidRoundNumber(); if ( block.timestamp >= correctRound.whenItWillUnlock && correctRound.unstakeUnlocked ) return true; else return false; } /** * @dev Method to get the expected amount of BKN tokens that the user can withdraw. * @param user address of the user */ function getProjectedAmount(address user) public view returns (uint256) { ( StakingRound storage correctRound, , bool itExists ) = _getStakingRoundByStaker(user); if (!itExists) return 0; uint256 lockedAmount = correctRound.userLockedFunds[user]; if (lockedAmount == 0) return 0; else return lockedAmount + lockedAmount.mulDiv( correctRound.amountToDistribute, correctRound.totalLocked ); } // Internal functions function _getStakingRoundByStaker( address user ) internal view returns ( StakingRound storage correctRound, uint256 roundId, bool itExists ) { return stakingRounds[1].userIsPresent[user] ? (stakingRounds[1], 1, true) : ( stakingRounds[2].userIsPresent[user] ? (stakingRounds[2], 2, true) : ( stakingRounds[3].userIsPresent[user] ? (stakingRounds[3], 3, true) : (stakingRounds[1], 1, false) ) ); } function _getStakingRoundById( uint8 round ) internal view returns (StakingRound storage correctRound, bool itExists) { return round == 1 ? (stakingRounds[1], true) : ( round == 2 ? (stakingRounds[2], true) : ( round == 3 ? (stakingRounds[3], true) : (stakingRounds[1], false) ) ); } /** * @dev Method to get whether the provided timestamp is in a valid staking period * and when the period will unlock the stake. */ function _getStakingPeriod( uint64 timeStamp ) internal view returns (bool, uint256) { if (timeStamp < stakingStart) return (false, 0); if ( timeStamp >= stakingStart && timeStamp < stakingRounds[1].whenItWillUnlock ) return (true, stakingRounds[1].whenItWillUnlock); else if ( timeStamp >= stakingRounds[1].whenItWillUnlock && timeStamp < stakingRounds[2].whenItWillUnlock ) return (true, stakingRounds[2].whenItWillUnlock); else if ( timeStamp >= stakingRounds[2].whenItWillUnlock && timeStamp < stakingRounds[3].whenItWillUnlock ) return (true, stakingRounds[3].whenItWillUnlock); return (false, 0); } /** * @dev Method to know if a given timestamp is withing a valid withdraw window */ function _isWithdrawPeriod(uint64 timeStamp) internal pure returns (bool) { if (timeStamp < window1Start) return false; else if (timeStamp >= window1Start && timeStamp < window1End) return true; else if (timeStamp >= window2Start && timeStamp < window2End) return true; else if (timeStamp >= window3Start) return true; else return false; } /** * @dev Method to get the current block.timestamp */ function _getTimestamp() internal view returns (uint256) { return block.timestamp; } }
// 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.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; import "../extensions/IERC20PermitUpgradeable.sol"; import "../../../utils/AddressUpgradeable.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 SafeERC20Upgradeable { using AddressUpgradeable 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(IERC20Upgradeable 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(IERC20Upgradeable 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(IERC20Upgradeable 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(IERC20Upgradeable 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(IERC20Upgradeable 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(IERC20Upgradeable 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( IERC20PermitUpgradeable 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(IERC20Upgradeable 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(IERC20Upgradeable 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))) && AddressUpgradeable.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @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 (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 IERC20PermitUpgradeable { /** * @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 IERC20Upgradeable { /** * @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 v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
{ "optimizer": { "enabled": true, "runs": 999 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "remappings": [] }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"AlreadyStaked","type":"error"},{"inputs":[],"name":"InvalidPeriod","type":"error"},{"inputs":[],"name":"InvalidRoundNumber","type":"error"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"available","type":"uint256"}],"name":"MaxToLockExceeded","type":"error"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"NotAllowedAllWBKN","type":"error"},{"inputs":[],"name":"NotContractAddress","type":"error"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"NotHolder","type":"error"},{"inputs":[],"name":"NotReleased","type":"error"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"NotStaker","type":"error"},{"inputs":[],"name":"NotZeroAddress","type":"error"},{"inputs":[],"name":"NotZeroValue","type":"error"},{"inputs":[],"name":"RoundPaused","type":"error"},{"inputs":[],"name":"UnableStake","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"round","type":"uint8"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"RoundPausedEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakingEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferUsersEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"round","type":"uint8"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"UnlockUnstakeEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"round","type":"uint8"}],"name":"UnstakingEvent","type":"event"},{"inputs":[],"name":"BKNToken","outputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WBKNToken","outputs":[{"internalType":"contract IWBKN","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"round","type":"uint8"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getDepositedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getProjectedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_WBKN","type":"address"},{"internalType":"address","name":"_BKN","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"isStaker","outputs":[{"internalType":"bool","name":"isUserStaker","type":"bool"},{"internalType":"uint256","name":"roundId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isStakingPeriod","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"round","type":"uint8"}],"name":"isUnstakeable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isWithdrawPeriod","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"round","type":"uint8"},{"internalType":"bool","name":"status","type":"bool"}],"name":"pauseRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakingRounds","outputs":[{"internalType":"bool","name":"statusPaused","type":"bool"},{"internalType":"bool","name":"unstakeUnlocked","type":"bool"},{"internalType":"uint256","name":"amountToDistribute","type":"uint256"},{"internalType":"uint256","name":"totalLocked","type":"uint256"},{"internalType":"uint256","name":"maxToLock","type":"uint256"},{"internalType":"uint256","name":"whenItWillUnlock","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"from","type":"uint8"},{"internalType":"uint8","name":"to","type":"uint8"},{"internalType":"address[]","name":"users","type":"address[]"}],"internalType":"struct Staking.TransferUsers","name":"transfer","type":"tuple"}],"name":"transferUsers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"round","type":"uint8"}],"name":"unlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"round","type":"uint8"},{"internalType":"bool","name":"status","type":"bool"}],"name":"unlockStaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Upgradeable","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405234801561001057600080fd5b5061001961001e565b6100dd565b600054610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116146100db576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6123a880620000ed6000396000f3fe6080604052600436106101485760003560e01c80638da5cb5b116100c0578063d509e8be11610074578063e9081ec711610059578063e9081ec7146103e8578063ebe41b7314610408578063f2fde38b1461042857600080fd5b8063d509e8be146103a8578063e53920b0146103c857600080fd5b80639d9d6ee3116100a55780639d9d6ee314610348578063bec315d614610368578063c0c53b8b1461038857600080fd5b80638da5cb5b146102f65780638f6d86751461032857600080fd5b80636f1e853311610117578063813f4db4116100fc578063813f4db41461029357806382266b9f146102a85780638a1577ef146102d657600080fd5b80636f1e853314610247578063715018a61461027e57600080fd5b8063094feeb41461015c578063294ae5e41461017c5780634f27c912146101a65780635fc3ea0b1461022757600080fd5b3661015757610155611f7d565b005b600080fd5b34801561016857600080fd5b50610155610177366004611fa4565b610448565b34801561018857600080fd5b506101916105ba565b60405190151581526020015b60405180910390f35b3480156101b257600080fd5b506101f86101c1366004611fbf565b6067602052600090815260409020805460018201546002830154600384015460069094015460ff8085169561010090950416939086565b6040805196151587529415156020870152938501929092526060840152608083015260a082015260c00161019d565b34801561023357600080fd5b50610155610242366004611fed565b6105ca565b34801561025357600080fd5b5061026761026236600461202f565b610676565b60408051921515835260208301919091520161019d565b34801561028a57600080fd5b506101556106a7565b34801561029f57600080fd5b506101916106bb565b3480156102b457600080fd5b506102c86102c336600461202f565b6106cc565b60405190815260200161019d565b3480156102e257600080fd5b506101556102f13660046120bc565b610744565b34801561030257600080fd5b506033546001600160a01b03165b6040516001600160a01b03909116815260200161019d565b34801561033457600080fd5b50606554610310906001600160a01b031681565b34801561035457600080fd5b506101556103633660046121cb565b6109b2565b34801561037457600080fd5b506101556103833660046121cb565b610a42565b34801561039457600080fd5b506101556103a3366004612202565b610ac0565b3480156103b457600080fd5b506101916103c3366004611fa4565b610e08565b3480156103d457600080fd5b50606654610310906001600160a01b031681565b3480156103f457600080fd5b506102c861040336600461202f565b610e6b565b34801561041457600080fd5b50610155610423366004611fa4565b610eaf565b34801561043457600080fd5b5061015561044336600461202f565b611361565b61045181610e08565b61046e5760405163f792d70360e01b815260040160405180910390fd5b3360008061047b836113f1565b9250509150806104c7576040517fbf2119490000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024015b60405180910390fd5b60068201544210806104e057508154610100900460ff16155b156104fe5760405163f792d70360e01b815260040160405180910390fd5b6000610509846106cc565b90508060000361052c57604051633fad6f3960e11b815260040160405180910390fd5b6001600160a01b0380851660009081526004850160209081526040808320839055600587019091529020805460ff1916905560655461056d91168583611591565b6040805182815260ff871660208201526001600160a01b038616917f55f2dad0879fb1838966ee9aaebe357c79a811852d0f45905b74fc550089803e910160405180910390a25050505050565b60006105c54261163f565b905090565b806001600160a01b03811661060b576040517f66385fa300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106136116f9565b8260000361063457604051633fad6f3960e11b815260040160405180910390fd5b6001600160a01b0384163b61065c5760405163d9716e4360e01b815260040160405180910390fd5b6106706001600160a01b0385168385611591565b50505050565b600080600080610685856113f1565b92509250508061069b5750600094909350915050565b50600194909350915050565b6106af6116f9565b6106b96000611753565b565b60006106c6426117b2565b50919050565b60008060006106da846113f1565b9250509150806106ee575060009392505050565b6001600160a01b03841660009081526004830160205260408120549081900361071c57506000949350505050565b600183015460028401546107319183916119d3565b61073b9082612258565b95945050505050565b61074c6116f9565b60005b8160400151518110156109705760008260400151828151811061077457610774612271565b60200260200101519050600061078982610e6b565b9050806000036107ac57604051633fad6f3960e11b815260040160405180910390fd5b836000015160ff16600314806107d05750836000015160ff16846020015160ff1611155b156107ee576040516320cbfb7560e11b815260040160405180910390fd5b6000806107fe8660000151611acb565b915091506000806108128860200151611acb565b91509150821580610821575080155b1561083f576040516320cbfb7560e11b815260040160405180910390fd5b6001600160a01b03861660009081526004850160205260408120819055600285018054879290610870908490612287565b90915550506001600160a01b03861660009081526005850160209081526040808320805460ff19169055600485019091529020859055600382015460028301546108bb908790612258565b11156109195785826002015483600301546108d69190612287565b6040517fff39f04f0000000000000000000000000000000000000000000000000000000081526001600160a01b03909216600483015260248201526044016104be565b8482600201600082825461092d9190612258565b9091555050506001600160a01b039094166000908152600590940160205250506040909120805460ff1916600117905550806109688161229a565b91505061074f565b507ffa0f93a400934e4b3bbd7d036133639cae7945a126437daab3f664f2874c33d48160400151516040516109a791815260200190565b60405180910390a150565b6109ba6116f9565b6000806109c684611acb565b91509150806109e8576040516320cbfb7560e11b815260040160405180910390fd5b815461ff0019166101008415159081029190911783556040805160ff8716815260208101929092527f5fe2e240a0b56a74dc093d2eaeb223e86a03b18e918a9434a7d687189e1fd6f391015b60405180910390a150505050565b610a4a6116f9565b600080610a5684611acb565b9150915080610a78576040516320cbfb7560e11b815260040160405180910390fd5b815460ff191683151590811783556040805160ff8716815260208101929092527fe35f4b320c058161cf8dc7c6536f8c79ec86eb3d2c2ffdb7a63cd3772687fd929101610a34565b600054610100900460ff1615808015610ae05750600054600160ff909116105b80610afa5750303b158015610afa575060005460ff166001145b610b6c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016104be565b6000805460ff191660011790558015610b8f576000805461ff0019166101001790555b6001600160a01b0384163b610bb75760405163d9716e4360e01b815260040160405180910390fd5b6001600160a01b0383163b610bdf5760405163d9716e4360e01b815260040160405180910390fd5b606680546001600160a01b0380871673ffffffffffffffffffffffffffffffffffffffff19928316179092556065805492861692909116919091179055610c24611bbe565b610c2c611c32565b610c3582611361565b6067602052636591f2707f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e7235563665a48607f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c54735563677477707f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f3c556a04f68ca6d8cd91c60000007f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e720556a069e10de76676d080000007f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c5470556a09195731e2ce35eb0000007f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f3955697f0e10af47c1c70000007f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e71e5569d3c21bcecceda10000007f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c546e5560036000526a01287626ee52197b0000007f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f37558015610670576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001610a34565b6000806000610e1684611acb565b9150915080610e38576040516320cbfb7560e11b815260040160405180910390fd5b81600601544210158015610e5257508154610100900460ff165b15610e61575060019392505050565b5060009392505050565b6000806000610e79846113f1565b925050915080610e8d575060009392505050565b506001600160a01b039092166000908152600490920160205250604090205490565b33610eb86106bb565b610eee576040517f17479ac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080610efa84611acb565b9150915080610f1c576040516320cbfb7560e11b815260040160405180910390fd5b815460ff1615610f58576040517f7f7c10f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610f6384610676565b5090508015610fa9576040517f0c45c8ec0000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016104be565b6066546040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b03868116600483015260009216906370a0823190602401602060405180830381865afa15801561100d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103191906122b3565b905080600003611078576040517fea4bef5b0000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201526024016104be565b6066546040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b038781166004830152306024830152600092169063dd62ed3e90604401602060405180830381865afa1580156110e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110691906122b3565b90508060000361112957604051633fad6f3960e11b815260040160405180910390fd5b8082111561116e576040517ff50643750000000000000000000000000000000000000000000000000000000081526001600160a01b03871660048201526024016104be565b84600301548286600201546111839190612258565b11156111a0578460020154856003015461119d9190612287565b91505b816000036111ec576040517fff39f04f0000000000000000000000000000000000000000000000000000000081526001600160a01b0387166004820152602481018390526044016104be565b606654611204906001600160a01b0316873085611c9d565b6066546040517f0357371d000000000000000000000000000000000000000000000000000000008152306004820152602481018490526000916001600160a01b031690630357371d906044016020604051808303816000875af115801561126f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061129391906122cc565b9050806112cc576040517f9316dab000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03871660009081526004870160209081526040808320869055600589019091528120805460ff19166001179055600287018054859290611314908490612258565b90915550506040518381526001600160a01b038816907fd213d1d108da45fd277b5e64582311022a00cfaee784c3045089ca4b22543bc79060200160405180910390a25050505050505050565b6113696116f9565b6001600160a01b0381166113e55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016104be565b6113ee81611753565b50565b6001600160a01b03811660009081527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e72260205260408120548190819060ff16611550576001600160a01b03841660009081527f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c5472602052604090205460ff1661151b576001600160a01b03841660009081527f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f3b602052604090205460ff166114e6576001600081815260676020527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e71d9190611580565b6003600081905260676020527f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f36906001611580565b6002600081905260676020527f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c546d906001611580565b6001600081905260676020527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e71d90805b91945060ff16925090509193909250565b6040516001600160a01b03831660248201526044810182905261163a9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611cee565b505050565b6000636592008067ffffffffffffffff8316101561165f57506000919050565b636592008067ffffffffffffffff83161080159061168a57506365badeff67ffffffffffffffff8316105b1561169757506001919050565b636681f18067ffffffffffffffff8316108015906116c257506366aacfff67ffffffffffffffff8316105b156116cf57506001919050565b636774858067ffffffffffffffff8316106116ec57506001919050565b506000919050565b919050565b6033546001600160a01b031633146106b95760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104be565b603380546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000806363b0cd0067ffffffffffffffff841610156117d657506000928392509050565b6363b0cd0067ffffffffffffffff8416108015906118285750600160005260676020527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e7235467ffffffffffffffff8416105b156118645750506001600081905260676020527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e723549092909150565b600160005260676020527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e7235467ffffffffffffffff8416108015906118dd5750600260005260676020527f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c54735467ffffffffffffffff8416105b1561191657505060026000525060676020527f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c547354600191565b600260005260676020527f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c54735467ffffffffffffffff84161080159061198f5750600360005260676020527f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f3c5467ffffffffffffffff8416105b156119c857505060036000525060676020527f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f3c54600191565b506000928392509050565b6000808060001985870985870292508281108382030391505080600003611a0d57838281611a0357611a036122e9565b0492505050611ac4565b808411611a5c5760405162461bcd60e51b815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f77000000000000000000000060448201526064016104be565b600084868809851960019081018716968790049682860381900495909211909303600082900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b6000808260ff16600114611b86578260ff16600214611b54578260ff16600314611b22576001600090815260676020527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e71d90611bb5565b600360005260676020527f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f366001611bb5565b600260005260676020527f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c546d6001611bb5565b6001600081905260676020527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e71d905b91509150915091565b600054610100900460ff16611c295760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016104be565b6106b933611753565b600054610100900460ff166106b95760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016104be565b6040516001600160a01b03808516602483015283166044820152606481018290526106709085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016115d6565b6000611d43826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611dd69092919063ffffffff16565b9050805160001480611d64575080806020019051810190611d6491906122cc565b61163a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016104be565b6060611de58484600085611ded565b949350505050565b606082471015611e655760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016104be565b600080866001600160a01b03168587604051611e819190612323565b60006040518083038185875af1925050503d8060008114611ebe576040519150601f19603f3d011682016040523d82523d6000602084013e611ec3565b606091505b5091509150611ed487838387611edf565b979650505050505050565b60608315611f4e578251600003611f47576001600160a01b0385163b611f475760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016104be565b5081611de5565b611de58383815115611f635781518083602001fd5b8060405162461bcd60e51b81526004016104be919061233f565b634e487b7160e01b600052600160045260246000fd5b803560ff811681146116f457600080fd5b600060208284031215611fb657600080fd5b611ac482611f93565b600060208284031215611fd157600080fd5b5035919050565b6001600160a01b03811681146113ee57600080fd5b60008060006060848603121561200257600080fd5b833561200d81611fd8565b925060208401359150604084013561202481611fd8565b809150509250925092565b60006020828403121561204157600080fd5b8135611ac481611fd8565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff811182821017156120855761208561204c565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156120b4576120b461204c565b604052919050565b600060208083850312156120cf57600080fd5b823567ffffffffffffffff808211156120e757600080fd5b90840190606082870312156120fb57600080fd5b612103612062565b61210c83611f93565b8152612119848401611f93565b8482015260408301358281111561212f57600080fd5b80840193505086601f84011261214457600080fd5b8235828111156121565761215661204c565b8060051b925061216785840161208b565b818152928401850192858101908985111561218157600080fd5b948601945b848610156121ab578535925061219b83611fd8565b8282529486019490860190612186565b60408401525090979650505050505050565b80151581146113ee57600080fd5b600080604083850312156121de57600080fd5b6121e783611f93565b915060208301356121f7816121bd565b809150509250929050565b60008060006060848603121561221757600080fd5b833561222281611fd8565b9250602084013561223281611fd8565b9150604084013561202481611fd8565b634e487b7160e01b600052601160045260246000fd5b8082018082111561226b5761226b612242565b92915050565b634e487b7160e01b600052603260045260246000fd5b8181038181111561226b5761226b612242565b6000600182016122ac576122ac612242565b5060010190565b6000602082840312156122c557600080fd5b5051919050565b6000602082840312156122de57600080fd5b8151611ac4816121bd565b634e487b7160e01b600052601260045260246000fd5b60005b8381101561231a578181015183820152602001612302565b50506000910152565b600082516123358184602087016122ff565b9190910192915050565b602081526000825180602084015261235e8160408501602087016122ff565b601f01601f1916919091016040019291505056fea264697066735822122088f1db58e1108e18c2ab5c78579c038b913995f52e039e51c16be1237fbb15b064736f6c63430008130033
Deployed Bytecode
0x6080604052600436106101485760003560e01c80638da5cb5b116100c0578063d509e8be11610074578063e9081ec711610059578063e9081ec7146103e8578063ebe41b7314610408578063f2fde38b1461042857600080fd5b8063d509e8be146103a8578063e53920b0146103c857600080fd5b80639d9d6ee3116100a55780639d9d6ee314610348578063bec315d614610368578063c0c53b8b1461038857600080fd5b80638da5cb5b146102f65780638f6d86751461032857600080fd5b80636f1e853311610117578063813f4db4116100fc578063813f4db41461029357806382266b9f146102a85780638a1577ef146102d657600080fd5b80636f1e853314610247578063715018a61461027e57600080fd5b8063094feeb41461015c578063294ae5e41461017c5780634f27c912146101a65780635fc3ea0b1461022757600080fd5b3661015757610155611f7d565b005b600080fd5b34801561016857600080fd5b50610155610177366004611fa4565b610448565b34801561018857600080fd5b506101916105ba565b60405190151581526020015b60405180910390f35b3480156101b257600080fd5b506101f86101c1366004611fbf565b6067602052600090815260409020805460018201546002830154600384015460069094015460ff8085169561010090950416939086565b6040805196151587529415156020870152938501929092526060840152608083015260a082015260c00161019d565b34801561023357600080fd5b50610155610242366004611fed565b6105ca565b34801561025357600080fd5b5061026761026236600461202f565b610676565b60408051921515835260208301919091520161019d565b34801561028a57600080fd5b506101556106a7565b34801561029f57600080fd5b506101916106bb565b3480156102b457600080fd5b506102c86102c336600461202f565b6106cc565b60405190815260200161019d565b3480156102e257600080fd5b506101556102f13660046120bc565b610744565b34801561030257600080fd5b506033546001600160a01b03165b6040516001600160a01b03909116815260200161019d565b34801561033457600080fd5b50606554610310906001600160a01b031681565b34801561035457600080fd5b506101556103633660046121cb565b6109b2565b34801561037457600080fd5b506101556103833660046121cb565b610a42565b34801561039457600080fd5b506101556103a3366004612202565b610ac0565b3480156103b457600080fd5b506101916103c3366004611fa4565b610e08565b3480156103d457600080fd5b50606654610310906001600160a01b031681565b3480156103f457600080fd5b506102c861040336600461202f565b610e6b565b34801561041457600080fd5b50610155610423366004611fa4565b610eaf565b34801561043457600080fd5b5061015561044336600461202f565b611361565b61045181610e08565b61046e5760405163f792d70360e01b815260040160405180910390fd5b3360008061047b836113f1565b9250509150806104c7576040517fbf2119490000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024015b60405180910390fd5b60068201544210806104e057508154610100900460ff16155b156104fe5760405163f792d70360e01b815260040160405180910390fd5b6000610509846106cc565b90508060000361052c57604051633fad6f3960e11b815260040160405180910390fd5b6001600160a01b0380851660009081526004850160209081526040808320839055600587019091529020805460ff1916905560655461056d91168583611591565b6040805182815260ff871660208201526001600160a01b038616917f55f2dad0879fb1838966ee9aaebe357c79a811852d0f45905b74fc550089803e910160405180910390a25050505050565b60006105c54261163f565b905090565b806001600160a01b03811661060b576040517f66385fa300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106136116f9565b8260000361063457604051633fad6f3960e11b815260040160405180910390fd5b6001600160a01b0384163b61065c5760405163d9716e4360e01b815260040160405180910390fd5b6106706001600160a01b0385168385611591565b50505050565b600080600080610685856113f1565b92509250508061069b5750600094909350915050565b50600194909350915050565b6106af6116f9565b6106b96000611753565b565b60006106c6426117b2565b50919050565b60008060006106da846113f1565b9250509150806106ee575060009392505050565b6001600160a01b03841660009081526004830160205260408120549081900361071c57506000949350505050565b600183015460028401546107319183916119d3565b61073b9082612258565b95945050505050565b61074c6116f9565b60005b8160400151518110156109705760008260400151828151811061077457610774612271565b60200260200101519050600061078982610e6b565b9050806000036107ac57604051633fad6f3960e11b815260040160405180910390fd5b836000015160ff16600314806107d05750836000015160ff16846020015160ff1611155b156107ee576040516320cbfb7560e11b815260040160405180910390fd5b6000806107fe8660000151611acb565b915091506000806108128860200151611acb565b91509150821580610821575080155b1561083f576040516320cbfb7560e11b815260040160405180910390fd5b6001600160a01b03861660009081526004850160205260408120819055600285018054879290610870908490612287565b90915550506001600160a01b03861660009081526005850160209081526040808320805460ff19169055600485019091529020859055600382015460028301546108bb908790612258565b11156109195785826002015483600301546108d69190612287565b6040517fff39f04f0000000000000000000000000000000000000000000000000000000081526001600160a01b03909216600483015260248201526044016104be565b8482600201600082825461092d9190612258565b9091555050506001600160a01b039094166000908152600590940160205250506040909120805460ff1916600117905550806109688161229a565b91505061074f565b507ffa0f93a400934e4b3bbd7d036133639cae7945a126437daab3f664f2874c33d48160400151516040516109a791815260200190565b60405180910390a150565b6109ba6116f9565b6000806109c684611acb565b91509150806109e8576040516320cbfb7560e11b815260040160405180910390fd5b815461ff0019166101008415159081029190911783556040805160ff8716815260208101929092527f5fe2e240a0b56a74dc093d2eaeb223e86a03b18e918a9434a7d687189e1fd6f391015b60405180910390a150505050565b610a4a6116f9565b600080610a5684611acb565b9150915080610a78576040516320cbfb7560e11b815260040160405180910390fd5b815460ff191683151590811783556040805160ff8716815260208101929092527fe35f4b320c058161cf8dc7c6536f8c79ec86eb3d2c2ffdb7a63cd3772687fd929101610a34565b600054610100900460ff1615808015610ae05750600054600160ff909116105b80610afa5750303b158015610afa575060005460ff166001145b610b6c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016104be565b6000805460ff191660011790558015610b8f576000805461ff0019166101001790555b6001600160a01b0384163b610bb75760405163d9716e4360e01b815260040160405180910390fd5b6001600160a01b0383163b610bdf5760405163d9716e4360e01b815260040160405180910390fd5b606680546001600160a01b0380871673ffffffffffffffffffffffffffffffffffffffff19928316179092556065805492861692909116919091179055610c24611bbe565b610c2c611c32565b610c3582611361565b6067602052636591f2707f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e7235563665a48607f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c54735563677477707f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f3c556a04f68ca6d8cd91c60000007f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e720556a069e10de76676d080000007f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c5470556a09195731e2ce35eb0000007f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f3955697f0e10af47c1c70000007f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e71e5569d3c21bcecceda10000007f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c546e5560036000526a01287626ee52197b0000007f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f37558015610670576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001610a34565b6000806000610e1684611acb565b9150915080610e38576040516320cbfb7560e11b815260040160405180910390fd5b81600601544210158015610e5257508154610100900460ff165b15610e61575060019392505050565b5060009392505050565b6000806000610e79846113f1565b925050915080610e8d575060009392505050565b506001600160a01b039092166000908152600490920160205250604090205490565b33610eb86106bb565b610eee576040517f17479ac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080610efa84611acb565b9150915080610f1c576040516320cbfb7560e11b815260040160405180910390fd5b815460ff1615610f58576040517f7f7c10f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610f6384610676565b5090508015610fa9576040517f0c45c8ec0000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016104be565b6066546040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b03868116600483015260009216906370a0823190602401602060405180830381865afa15801561100d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103191906122b3565b905080600003611078576040517fea4bef5b0000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201526024016104be565b6066546040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b038781166004830152306024830152600092169063dd62ed3e90604401602060405180830381865afa1580156110e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110691906122b3565b90508060000361112957604051633fad6f3960e11b815260040160405180910390fd5b8082111561116e576040517ff50643750000000000000000000000000000000000000000000000000000000081526001600160a01b03871660048201526024016104be565b84600301548286600201546111839190612258565b11156111a0578460020154856003015461119d9190612287565b91505b816000036111ec576040517fff39f04f0000000000000000000000000000000000000000000000000000000081526001600160a01b0387166004820152602481018390526044016104be565b606654611204906001600160a01b0316873085611c9d565b6066546040517f0357371d000000000000000000000000000000000000000000000000000000008152306004820152602481018490526000916001600160a01b031690630357371d906044016020604051808303816000875af115801561126f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061129391906122cc565b9050806112cc576040517f9316dab000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03871660009081526004870160209081526040808320869055600589019091528120805460ff19166001179055600287018054859290611314908490612258565b90915550506040518381526001600160a01b038816907fd213d1d108da45fd277b5e64582311022a00cfaee784c3045089ca4b22543bc79060200160405180910390a25050505050505050565b6113696116f9565b6001600160a01b0381166113e55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016104be565b6113ee81611753565b50565b6001600160a01b03811660009081527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e72260205260408120548190819060ff16611550576001600160a01b03841660009081527f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c5472602052604090205460ff1661151b576001600160a01b03841660009081527f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f3b602052604090205460ff166114e6576001600081815260676020527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e71d9190611580565b6003600081905260676020527f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f36906001611580565b6002600081905260676020527f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c546d906001611580565b6001600081905260676020527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e71d90805b91945060ff16925090509193909250565b6040516001600160a01b03831660248201526044810182905261163a9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611cee565b505050565b6000636592008067ffffffffffffffff8316101561165f57506000919050565b636592008067ffffffffffffffff83161080159061168a57506365badeff67ffffffffffffffff8316105b1561169757506001919050565b636681f18067ffffffffffffffff8316108015906116c257506366aacfff67ffffffffffffffff8316105b156116cf57506001919050565b636774858067ffffffffffffffff8316106116ec57506001919050565b506000919050565b919050565b6033546001600160a01b031633146106b95760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104be565b603380546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000806363b0cd0067ffffffffffffffff841610156117d657506000928392509050565b6363b0cd0067ffffffffffffffff8416108015906118285750600160005260676020527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e7235467ffffffffffffffff8416105b156118645750506001600081905260676020527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e723549092909150565b600160005260676020527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e7235467ffffffffffffffff8416108015906118dd5750600260005260676020527f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c54735467ffffffffffffffff8416105b1561191657505060026000525060676020527f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c547354600191565b600260005260676020527f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c54735467ffffffffffffffff84161080159061198f5750600360005260676020527f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f3c5467ffffffffffffffff8416105b156119c857505060036000525060676020527f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f3c54600191565b506000928392509050565b6000808060001985870985870292508281108382030391505080600003611a0d57838281611a0357611a036122e9565b0492505050611ac4565b808411611a5c5760405162461bcd60e51b815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f77000000000000000000000060448201526064016104be565b600084868809851960019081018716968790049682860381900495909211909303600082900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b6000808260ff16600114611b86578260ff16600214611b54578260ff16600314611b22576001600090815260676020527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e71d90611bb5565b600360005260676020527f8c1c91810985109892a55558a5891c2831cd29dc314f55daca604b52719f9f366001611bb5565b600260005260676020527f34a128ff2438bccb68124de780ea45be60aca78c6fb6ce114324ee2dd88c546d6001611bb5565b6001600081905260676020527f6bee784efeb983674392298ab585b22866bedf00ebb0eea949d1e66f3f50e71d905b91509150915091565b600054610100900460ff16611c295760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016104be565b6106b933611753565b600054610100900460ff166106b95760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016104be565b6040516001600160a01b03808516602483015283166044820152606481018290526106709085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016115d6565b6000611d43826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611dd69092919063ffffffff16565b9050805160001480611d64575080806020019051810190611d6491906122cc565b61163a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016104be565b6060611de58484600085611ded565b949350505050565b606082471015611e655760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016104be565b600080866001600160a01b03168587604051611e819190612323565b60006040518083038185875af1925050503d8060008114611ebe576040519150601f19603f3d011682016040523d82523d6000602084013e611ec3565b606091505b5091509150611ed487838387611edf565b979650505050505050565b60608315611f4e578251600003611f47576001600160a01b0385163b611f475760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016104be565b5081611de5565b611de58383815115611f635781518083602001fd5b8060405162461bcd60e51b81526004016104be919061233f565b634e487b7160e01b600052600160045260246000fd5b803560ff811681146116f457600080fd5b600060208284031215611fb657600080fd5b611ac482611f93565b600060208284031215611fd157600080fd5b5035919050565b6001600160a01b03811681146113ee57600080fd5b60008060006060848603121561200257600080fd5b833561200d81611fd8565b925060208401359150604084013561202481611fd8565b809150509250925092565b60006020828403121561204157600080fd5b8135611ac481611fd8565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff811182821017156120855761208561204c565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156120b4576120b461204c565b604052919050565b600060208083850312156120cf57600080fd5b823567ffffffffffffffff808211156120e757600080fd5b90840190606082870312156120fb57600080fd5b612103612062565b61210c83611f93565b8152612119848401611f93565b8482015260408301358281111561212f57600080fd5b80840193505086601f84011261214457600080fd5b8235828111156121565761215661204c565b8060051b925061216785840161208b565b818152928401850192858101908985111561218157600080fd5b948601945b848610156121ab578535925061219b83611fd8565b8282529486019490860190612186565b60408401525090979650505050505050565b80151581146113ee57600080fd5b600080604083850312156121de57600080fd5b6121e783611f93565b915060208301356121f7816121bd565b809150509250929050565b60008060006060848603121561221757600080fd5b833561222281611fd8565b9250602084013561223281611fd8565b9150604084013561202481611fd8565b634e487b7160e01b600052601160045260246000fd5b8082018082111561226b5761226b612242565b92915050565b634e487b7160e01b600052603260045260246000fd5b8181038181111561226b5761226b612242565b6000600182016122ac576122ac612242565b5060010190565b6000602082840312156122c557600080fd5b5051919050565b6000602082840312156122de57600080fd5b8151611ac4816121bd565b634e487b7160e01b600052601260045260246000fd5b60005b8381101561231a578181015183820152602001612302565b50506000910152565b600082516123358184602087016122ff565b9190910192915050565b602081526000825180602084015261235e8160408501602087016122ff565b601f01601f1916919091016040019291505056fea264697066735822122088f1db58e1108e18c2ab5c78579c038b913995f52e039e51c16be1237fbb15b064736f6c63430008130033
Deployed Bytecode Sourcemap
623:18040:9:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6150:13;;:::i;:::-;623:18040;;;;;12189:937;;;;;;;;;;-1:-1:-1;12189:937:9;;;;;:::i;:::-;;:::i;13952:130::-;;;;;;;;;;;;;:::i;:::-;;;716:14:10;;709:22;691:41;;679:2;664:18;13952:130:9;;;;;;;;3418:53;;;;;;;;;;-1:-1:-1;3418:53:9;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1228:14:10;;1221:22;1203:41;;1287:14;;1280:22;1275:2;1260:18;;1253:50;1319:18;;;1312:34;;;;1377:2;1362:18;;1355:34;1420:3;1405:19;;1398:35;1464:3;1449:19;;1442:35;1190:3;1175:19;3418:53:9;928:555:10;7060:372:9;;;;;;;;;;-1:-1:-1;7060:372:9;;;;;:::i;:::-;;:::i;14196:261::-;;;;;;;;;;-1:-1:-1;14196:261:9;;;;;:::i;:::-;;:::i;:::-;;;;2654:14:10;;2647:22;2629:41;;2701:2;2686:18;;2679:34;;;;2602:18;14196:261:9;2461:258:10;2064:101:0;;;;;;;;;;;;;:::i;13706:133:9:-;;;;;;;;;;;;;:::i;15155:581::-;;;;;;;;;;-1:-1:-1;15155:581:9;;;;;:::i;:::-;;:::i;:::-;;;2870:25:10;;;2858:2;2843:18;15155:581:9;2724:177:10;8125:1648:9;;;;;;;;;;-1:-1:-1;8125:1648:9;;;;;:::i;:::-;;:::i;1441:85:0:-;;;;;;;;;;-1:-1:-1;1513:6:0;;-1:-1:-1;;;;;1513:6:0;1441:85;;;-1:-1:-1;;;;;5229:55:10;;;5211:74;;5199:2;5184:18;1441:85:0;5065:226:10;2424:33:9;;;;;;;;;;-1:-1:-1;2424:33:9;;;;-1:-1:-1;;;;;2424:33:9;;;7636:348;;;;;;;;;;-1:-1:-1;7636:348:9;;;;;:::i;:::-;;:::i;6538:338::-;;;;;;;;;;-1:-1:-1;6538:338:9;;;;;:::i;:::-;;:::i;4949:1079::-;;;;;;;;;;-1:-1:-1;4949:1079:9;;;;;:::i;:::-;;:::i;14592:414::-;;;;;;;;;;-1:-1:-1;14592:414:9;;;;;:::i;:::-;;:::i;2463:22::-;;;;;;;;;;-1:-1:-1;2463:22:9;;;;-1:-1:-1;;;;;2463:22:9;;;13285:310;;;;;;;;;;-1:-1:-1;13285:310:9;;;;;:::i;:::-;;:::i;10162:1738::-;;;;;;;;;;-1:-1:-1;10162:1738:9;;;;;:::i;:::-;;:::i;2314:198:0:-;;;;;;;;;;-1:-1:-1;2314:198:0;;;;;:::i;:::-;;:::i;12189:937:9:-;12242:20;12256:5;12242:13;:20::i;:::-;12237:47;;12271:13;;-1:-1:-1;;;12271:13:9;;;;;;;;;;;12237:47;929:10:6;12295:14:9;;12436:32;929:10:6;12436:24:9;:32::i;:::-;12335:133;;;;;12528:8;12523:39;;12545:17;;;;;-1:-1:-1;;;;;5229:55:10;;12545:17:9;;;5211:74:10;5184:18;;12545:17:9;;;;;;;;12523:39;12611:29;;;;12592:15;:48;;12590:96;;-1:-1:-1;12658:28:9;;;;;;;12657:29;12590:96;12573:144;;;12704:13;;-1:-1:-1;;;12704:13:9;;;;;;;;;;;12573:144;12788:14;12805:26;12824:6;12805:18;:26::i;:::-;12788:43;;12845:6;12855:1;12845:11;12841:38;;12865:14;;-1:-1:-1;;;12865:14:9;;;;;;;;;;;12841:38;-1:-1:-1;;;;;12890:36:9;;;12929:1;12890:36;;;:28;;;:36;;;;;;;;:40;;;12940:26;;;:34;;;;;:42;;-1:-1:-1;;12940:42:9;;;13029:8;;:37;;:8;12919:6;13059;13029:21;:37::i;:::-;13082;;;6997:25:10;;;7070:4;7058:17;;7053:2;7038:18;;7031:45;-1:-1:-1;;;;;13082:37:9;;;;;6970:18:10;13082:37:9;;;;;;;12227:899;;;;12189:937;:::o;13952:130::-;14001:11;14033:42;18639:15;14033:17;:42::i;:::-;14024:51;;13952:130;:::o;7060:372::-;7188:2;-1:-1:-1;;;;;6340:16:9;;6336:45;;6365:16;;;;;;;;;;;;;;6336:45;1334:13:0::1;:11;:13::i;:::-;7216:6:9::2;7226:1;7216:11:::0;7212:38:::2;;7236:14;;-1:-1:-1::0;;;7236:14:9::2;;;;;;;;;;;7212:38;-1:-1:-1::0;;;;;7265:25:9;::::2;1702:19:7::0;7260:61:9::2;;7301:20;;-1:-1:-1::0;;;7301:20:9::2;;;;;;;;;;;7260:61;7331:30;-1:-1:-1::0;;;;;7331:18:9;::::2;7350:2:::0;7354:6;7331:18:::2;:30::i;:::-;7060:372:::0;;;;:::o;14196:261::-;14263:17;14282:12;14309;14323:13;14340:30;14365:4;14340:24;:30::i;:::-;14306:64;;;;;14385:8;14380:38;;-1:-1:-1;14403:5:9;;14410:7;;-1:-1:-1;14196:261:9;-1:-1:-1;;14196:261:9:o;14380:38::-;-1:-1:-1;14436:4:9;;14442:7;;-1:-1:-1;14196:261:9;-1:-1:-1;;14196:261:9:o;2064:101:0:-;1334:13;:11;:13::i;:::-;2128:30:::1;2155:1;2128:18;:30::i;:::-;2064:101::o:0;13706:133:9:-;13754:11;13790:42;18639:15;13790:17;:42::i;:::-;-1:-1:-1;13777:55:9;13706:133;-1:-1:-1;13706:133:9:o;15155:581::-;15218:7;15251:33;15312:13;15338:30;15363:4;15338:24;:30::i;:::-;15237:131;;;;;15384:8;15379:23;;-1:-1:-1;15401:1:9;;15155:581;-1:-1:-1;;;15155:581:9:o;15379:23::-;-1:-1:-1;;;;;15436:34:9;;15413:20;15436:34;;;:28;;;:34;;;;;;;15485:17;;;15481:248;;-1:-1:-1;15511:1:9;;15155:581;-1:-1:-1;;;;15155:581:9:o;15481:248::-;15634:31;;;;15687:24;;;;15593:136;;:12;;:19;:136::i;:::-;15562:167;;:12;:167;:::i;:::-;15539:190;15155:581;-1:-1:-1;;;;;15155:581:9:o;8125:1648::-;1334:13:0;:11;:13::i;:::-;8309:9:9::1;8304:1406;8328:8;:14;;;:21;8324:1;:25;8304:1406;;;8370:12;8385:8;:14;;;8400:1;8385:17;;;;;;;;:::i;:::-;;;;;;;8370:32;;8416:14;8433:24;8452:4;8433:18;:24::i;:::-;8416:41;;8475:6;8485:1;8475:11:::0;8471:38:::1;;8495:14;;-1:-1:-1::0;;;8495:14:9::1;;;;;;;;;;;8471:38;8642:8;:13;;;:18;;8659:1;8642:18;:50;;;;8679:8;:13;;;8664:28;;:8;:11;;;:28;;;;8642:50;8638:99;;;8717:20;;-1:-1:-1::0;;;8717:20:9::1;;;;;;;;;;;8638:99;8861:30;8909:13:::0;8939:35:::1;8960:8;:13;;;8939:20;:35::i;:::-;8843:131;;;;9006:28;9052:17:::0;9086:33:::1;9107:8;:11;;;9086:20;:33::i;:::-;8988:131;;;;9138:8;9137:9;:26;;;;9151:12;9150:13;9137:26;9133:59;;;9172:20;;-1:-1:-1::0;;;9172:20:9::1;;;;;;;;;;;9133:59;-1:-1:-1::0;;;;;9207:31:9;::::1;9241:1;9207:31:::0;;;:25:::1;::::0;::::1;:31;::::0;;;;:35;;;9256:21:::1;::::0;::::1;:31:::0;;9281:6;;9241:1;9256:31:::1;::::0;9281:6;;9256:31:::1;:::i;:::-;::::0;;;-1:-1:-1;;;;;;;9301:29:9;::::1;9333:5;9301:29:::0;;;:23:::1;::::0;::::1;:29;::::0;;;;;;;:37;;-1:-1:-1;;9301:37:9::1;::::0;;9353:23:::1;::::0;::::1;:29:::0;;;;;:38;;;9443:17:::1;::::0;::::1;::::0;9411:19:::1;::::0;::::1;::::0;:28:::1;::::0;9385:6;;9411:28:::1;:::i;:::-;9410:50;9406:201;;;9524:4;9570:7;:19;;;9550:7;:17;;;:39;;;;:::i;:::-;9485:122;::::0;::::1;::::0;;-1:-1:-1;;;;;7920:55:10;;;9485:122:9::1;::::0;::::1;7902:74:10::0;7992:18;;;7985:34;7875:18;;9485:122:9::1;7728:297:10::0;9406:201:9::1;9645:6;9622:7;:19;;;:29;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;;;;;;;9665:27:9;;::::1;;::::0;;;:21:::1;::::0;;::::1;:27;::::0;-1:-1:-1;;9665:27:9;;;;:34;;-1:-1:-1;;9665:34:9::1;9695:4;9665:34;::::0;;-1:-1:-1;8351:3:9;::::1;::::0;::::1;:::i;:::-;;;;8304:1406;;;;9725:41;9744:8;:14;;;:21;9725:41;;;;2870:25:10::0;;2858:2;2843:18;;2724:177;9725:41:9::1;;;;;;;;8125:1648:::0;:::o;7636:348::-;1334:13:0;:11;:13::i;:::-;7728:33:9::1;7775:13:::0;7801:27:::1;7822:5;7801:20;:27::i;:::-;7714:114;;;;7843:8;7838:42;;7860:20;;-1:-1:-1::0;;;7860:20:9::1;;;;;;;;;;;7838:42;7891:37:::0;;-1:-1:-1;;7891:37:9::1;;::::0;::::1;;::::0;;::::1;::::0;;;::::1;::::0;;7944:33:::1;::::0;;8364:4:10;8352:17;;8334:36;;8401:2;8386:18;;8379:50;;;;7944:33:9::1;::::0;8307:18:10;7944:33:9::1;;;;;;;;7704:280;;7636:348:::0;;:::o;6538:338::-;1334:13:0;:11;:13::i;:::-;6627:33:9::1;6674:13:::0;6700:27:::1;6721:5;6700:20;:27::i;:::-;6613:114;;;;6741:8;6737:41;;6758:20;;-1:-1:-1::0;;;6758:20:9::1;;;;;;;;;;;6737:41;6789:34:::0;;-1:-1:-1;;6789:34:9::1;::::0;::::1;;::::0;;::::1;::::0;;6838:31:::1;::::0;;8364:4:10;8352:17;;8334:36;;8401:2;8386:18;;8379:50;;;;6838:31:9::1;::::0;8307:18:10;6838:31:9::1;8170:265:10::0;4949:1079:9;3279:19:1;3302:13;;;;;;3301:14;;3347:34;;;;-1:-1:-1;3365:12:1;;3380:1;3365:12;;;;:16;3347:34;3346:108;;;-1:-1:-1;3426:4:1;1702:19:7;:23;;;3387:66:1;;-1:-1:-1;3436:12:1;;;;;:17;3387:66;3325:201;;;;-1:-1:-1;;;3325:201:1;;8642:2:10;3325:201:1;;;8624:21:10;8681:2;8661:18;;;8654:30;8720:34;8700:18;;;8693:62;8791:16;8771:18;;;8764:44;8825:19;;3325:201:1;8440:410:10;3325:201:1;3536:12;:16;;-1:-1:-1;;3536:16:1;3551:1;3536:16;;;3562:65;;;;3596:13;:20;;-1:-1:-1;;3596:20:1;;;;;3562:65;-1:-1:-1;;;;;5052:16:9;::::1;1702:19:7::0;5047:52:9::1;;5079:20;;-1:-1:-1::0;;;5079:20:9::1;;;;;;;;;;;5047:52;-1:-1:-1::0;;;;;5114:15:9;::::1;1702:19:7::0;5109:51:9::1;;5140:20;;-1:-1:-1::0;;;5140:20:9::1;;;;;;;;;;;5109:51;5171:9;:24:::0;;-1:-1:-1;;;;;5171:24:9;;::::1;-1:-1:-1::0;;5171:24:9;;::::1;;::::0;;;5205:8:::1;:34:::0;;;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;5250:26:::1;:24;:26::i;:::-;5286;:24;:26::i;:::-;5322:25;5340:6;5322:17;:25::i;:::-;5410:13;:16;::::0;5446:10:::1;5410:33:::0;:46;5555:10:::1;5519:33:::0;:46;5664:10:::1;5628:33:::0;:46;5739:4:::1;5710:26:::0;:33;5782:4:::1;5753:26:::0;:33;5825:5:::1;5796:26:::0;:34;5911:4:::1;5873:35:::0;:42;5963:5:::1;5925:35:::0;:43;5642:1:::1;5410:16;5978::::0;6016:5:::1;5978:35:::0;:43;3647:99:1;;;;3697:5;3681:21;;-1:-1:-1;;3681:21:1;;;3721:14;;-1:-1:-1;9007:36:10;;3721:14:1;;8995:2:10;8980:18;3721:14:1;8855:194:10;14592:414:9;14649:4;14679:33;14726:13;14752:27;14773:5;14752:20;:27::i;:::-;14665:114;;;;14794:8;14789:42;;14811:20;;-1:-1:-1;;;14811:20:9;;;;;;;;;;;14789:42;14877:12;:29;;;14858:15;:48;;:92;;;;-1:-1:-1;14922:28:9;;;;;;;14858:92;14841:158;;;-1:-1:-1;14968:4:9;;14592:414;-1:-1:-1;;;14592:414:9:o;14841:158::-;-1:-1:-1;14994:5:9;;14592:414;-1:-1:-1;;;14592:414:9:o;13285:310::-;13348:7;13381:33;13442:13;13468:30;13493:4;13468:24;:30::i;:::-;13367:131;;;;;13514:8;13509:79;;-1:-1:-1;13531:1:9;;13285:310;-1:-1:-1;;;13285:310:9:o;13509:79::-;-1:-1:-1;;;;;;13554:34:9;;;;;;;:28;;;;:34;;-1:-1:-1;13554:34:9;;;;;13285:310::o;10162:1738::-;929:10:6;10313:17:9;:15;:17::i;:::-;10308:46;;10339:15;;;;;;;;;;;;;;10308:46;10379:33;10426:13;10452:27;10473:5;10452:20;:27::i;:::-;10365:114;;;;10495:8;10490:42;;10512:20;;-1:-1:-1;;;10512:20:9;;;;;;;;;;;10490:42;10547:25;;;;10543:51;;;10581:13;;;;;;;;;;;;;;10543:51;10650:17;10673:16;10682:6;10673:8;:16::i;:::-;10649:40;;;10703:12;10699:46;;;10724:21;;;;;-1:-1:-1;;;;;5229:55:10;;10724:21:9;;;5211:74:10;5184:18;;10724:21:9;5065:226:10;10699:46:9;10831:9;;:27;;;;;-1:-1:-1;;;;;5229:55:10;;;10831:27:9;;;5211:74:10;10814:14:9;;10831:9;;:19;;5184:18:10;;10831:27:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10814:44;;10872:6;10882:1;10872:11;10868:41;;10892:17;;;;;-1:-1:-1;;;;;5229:55:10;;10892:17:9;;;5211:74:10;5184:18;;10892:17:9;5065:226:10;10868:41:9;11018:9;;:42;;;;;-1:-1:-1;;;;;9496:15:10;;;11018:42:9;;;9478:34:10;11054:4:9;9528:18:10;;;9521:43;11000:15:9;;11018:9;;:19;;9390:18:10;;11018:42:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11000:60;;11074:7;11085:1;11074:12;11070:39;;11095:14;;-1:-1:-1;;;11095:14:9;;;;;;;;;;;11070:39;11132:7;11123:6;:16;11119:54;;;11148:25;;;;;-1:-1:-1;;;;;5229:55:10;;11148:25:9;;;5211:74:10;5184:18;;11148:25:9;5065:226:10;11119:54:9;11292:12;:22;;;11282:6;11255:12;:24;;;:33;;;;:::i;:::-;11254:60;11250:136;;;11362:12;:24;;;11337:12;:22;;;:49;;;;:::i;:::-;11328:58;;11250:136;11400:6;11410:1;11400:11;11396:57;;11420:33;;;;;-1:-1:-1;;;;;7920:55:10;;11420:33:9;;;7902:74:10;7992:18;;;7985:34;;;7875:18;;11420:33:9;7728:297:10;11396:57:9;11531:9;;:57;;-1:-1:-1;;;;;11531:9:9;11558:6;11574:4;11581:6;11531:26;:57::i;:::-;11614:9;;:40;;;;;11640:4;11614:40;;;7902:74:10;7992:18;;;7985:34;;;11599:12:9;;-1:-1:-1;;;;;11614:9:9;;:17;;7875:18:10;;11614:40:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11599:55;;11669:7;11664:34;;11685:13;;;;;;;;;;;;;;11664:34;-1:-1:-1;;;;;11709:36:9;;;;;;:28;;;:36;;;;;;;;:45;;;11764:26;;;:34;;;;;:41;;-1:-1:-1;;11764:41:9;11801:4;11764:41;;;11815:24;;;:34;;11748:6;;11709:36;11815:34;;11748:6;;11815:34;:::i;:::-;;;;-1:-1:-1;;11865:28:9;;2870:25:10;;;-1:-1:-1;;;;;11865:28:9;;;;;2858:2:10;2843:18;11865:28:9;;;;;;;10201:1699;;;;;;;10162:1738;:::o;2314:198:0:-;1334:13;:11;:13::i;:::-;-1:-1:-1;;;;;2402:22:0;::::1;2394:73;;;::::0;-1:-1:-1;;;2394:73:0;;10027:2:10;2394:73:0::1;::::0;::::1;10009:21:10::0;10066:2;10046:18;;;10039:30;10105:34;10085:18;;;10078:62;10176:8;10156:18;;;10149:36;10202:19;;2394:73:0::1;9825:402:10::0;2394:73:0::1;2477:28;2496:8;2477:18;:28::i;:::-;2314:198:::0;:::o;15769:737:9:-;-1:-1:-1;;;;;16024:36:9;;15891:33;16024:36;;;:30;:16;:36;:16;:36;;;15891:33;;;;16024:36;;:475;;-1:-1:-1;;;;;16147:36:9;;:16;:36;;;:30;:16;:36;:16;:36;;;;;:334;;-1:-1:-1;;;;;16294:36:9;;:16;:36;;;:30;:16;:36;:16;:36;;;;;:161;;16442:1;16428:16;;;;:13;:16;;;;16442:1;16024:475;;16294:161;16380:1;16366:16;;;;:13;:16;;;;16387:4;16024:475;;16147:334;16225:1;16211:16;;;;:13;:16;;;;16232:4;16024:475;;;16094:1;16080:16;;;;:13;:16;;;;16094:1;16024:475;16005:494;;-1:-1:-1;16005:494:9;;;-1:-1:-1;16005:494:9;-1:-1:-1;15769:737:9;;;;;:::o;996:186:4:-;1116:58;;-1:-1:-1;;;;;7920:55:10;;1116:58:4;;;7902:74:10;7992:18;;;7985:34;;;1089:86:4;;1109:5;;1139:23;;7875:18:10;;1116:58:4;;;;-1:-1:-1;;1116:58:4;;;;;;;;;;;;;;;;;;;;;;;;;;;1089:19;:86::i;:::-;996:186;;;:::o;18082:407:9:-;18150:4;1946:10;18170:24;;;;18166:316;;;-1:-1:-1;18203:5:9;;18082:407;-1:-1:-1;18082:407:9:o;18166:316::-;1946:10;18227:25;;;;;;;:51;;-1:-1:-1;1999:10:9;18256:22;;;;18227:51;18223:259;;;-1:-1:-1;18299:4:9;;18082:407;-1:-1:-1;18082:407:9:o;18223:259::-;2123:10;18322:25;;;;;;;:51;;-1:-1:-1;2176:10:9;18351:22;;;;18322:51;18318:164;;;-1:-1:-1;18394:4:9;;18082:407;-1:-1:-1;18082:407:9:o;18318:164::-;2287:10;18417:25;;;;18413:69;;-1:-1:-1;18451:4:9;;18082:407;-1:-1:-1;18082:407:9:o;18413:69::-;-1:-1:-1;18477:5:9;;18082:407;-1:-1:-1;18082:407:9:o;18413:69::-;18082:407;;;:::o;1599:130:0:-;1513:6;;-1:-1:-1;;;;;1513:6:0;929:10:6;1662:23:0;1654:68;;;;-1:-1:-1;;;1654:68:0;;10434:2:10;1654:68:0;;;10416:21:10;;;10453:18;;;10446:30;10512:34;10492:18;;;10485:62;10564:18;;1654:68:0;10232:356:10;2666:187:0;2758:6;;;-1:-1:-1;;;;;2774:17:0;;;-1:-1:-1;;2774:17:0;;;;;;;2806:40;;2758:6;;;2774:17;2758:6;;2806:40;;2739:16;;2806:40;2729:124;2666:187;:::o;17221:756:9:-;17303:4;;2374:10;17332:24;;;;17328:47;;;-1:-1:-1;17366:5:9;;;;-1:-1:-1;17221:756:9;-1:-1:-1;17221:756:9:o;17328:47::-;2374:10;17402:25;;;;;;;:86;;-1:-1:-1;17469:1:9;17455:16;;:13;:16;;:33;;17443:45;;;;17402:86;17385:558;;;-1:-1:-1;;17507:4:9;17513:16;;;;:13;:16;;:33;;17507:4;;17513:33;;-1:-1:-1;17221:756:9:o;17385:558::-;17606:1;17592:16;;:13;:16;;:33;;17579:46;;;;;;;:107;;-1:-1:-1;17667:1:9;17653:16;;:13;:16;;:33;;17641:45;;;;17579:107;17562:381;;;-1:-1:-1;;17725:1:9;17711:16;;-1:-1:-1;17711:13:9;:16;;:33;;17705:4;;17221:756::o;17562:381::-;17804:1;17790:16;;:13;:16;;:33;;17777:46;;;;;;;:107;;-1:-1:-1;17865:1:9;17851:16;;:13;:16;;:33;;17839:45;;;;17777:107;17760:183;;;-1:-1:-1;;17923:1:9;17909:16;;-1:-1:-1;17909:13:9;:16;;:33;;17903:4;;17221:756::o;17760:183::-;-1:-1:-1;17961:5:9;;;;-1:-1:-1;17221:756:9;-1:-1:-1;17221:756:9:o;1667:4213:8:-;1749:14;;;-1:-1:-1;;2286:1:8;2283;2276:20;2329:1;2326;2322:9;2313:18;;2384:5;2380:2;2377:13;2369:5;2365:2;2361:14;2357:34;2348:43;;;2486:5;2495:1;2486:10;2482:368;;2824:11;2816:5;:19;;;;;:::i;:::-;;2809:26;;;;;;2482:368;2974:5;2960:11;:19;2952:53;;;;-1:-1:-1;;;2952:53:8;;10984:2:10;2952:53:8;;;10966:21:10;11023:2;11003:18;;;10996:30;11062:23;11042:18;;;11035:51;11103:18;;2952:53:8;10782:345:10;2952:53:8;3261:17;3396:11;3393:1;3390;3383:25;3929:12;;3944:1;3929:16;;;3914:32;;4049:22;;;;;3557:21;;;4147:16;;;3510:20;;;;3499:32;;;3899:12;4294;;;4290:23;;;;4286:31;;;4406:12;;;;4397:21;;;;4755:1;:15;;4774:1;4754:21;;;5007;;;5003:25;;4992:36;5076:21;;;5072:25;;5061:36;5146:21;;;5142:25;;5131:36;5216:21;;;5212:25;;5201:36;5286:21;;;5282:25;;5271:36;5357:21;;;5353:25;;;5342:36;5821:15;;-1:-1:-1;;1667:4213:8;;;;;;:::o;16512:551:9:-;16592:33;16627:13;16671:5;:10;;16680:1;16671:10;:385;;16765:5;:10;;16774:1;16765:10;:273;;16883:5;:10;;16892:1;16883:10;:129;;17002:1;16988:16;;;;:13;:16;;;;16671:385;;16883:129;16943:1;16929:16;;:13;:16;;;16947:4;16671:385;;16765:273;16817:1;16803:16;;:13;:16;;;16821:4;16671:385;;;16715:1;16701:16;;;;:13;:16;;;;16671:385;16652:404;;;;16512:551;;;:::o;1104:111:0:-;5374:13:1;;;;;;;5366:69;;;;-1:-1:-1;;;5366:69:1;;11334:2:10;5366:69:1;;;11316:21:10;11373:2;11353:18;;;11346:30;11412:34;11392:18;;;11385:62;-1:-1:-1;;;11463:18:10;;;11456:41;11514:19;;5366:69:1;11132:407:10;5366:69:1;1176:32:0::1;929:10:6::0;1176:18:0::1;:32::i;776:69:6:-:0;5374:13:1;;;;;;;5366:69;;;;-1:-1:-1;;;5366:69:1;;11334:2:10;5366:69:1;;;11316:21:10;11373:2;11353:18;;;11346:30;11412:34;11392:18;;;11385:62;-1:-1:-1;;;11463:18:10;;;11456:41;11514:19;;5366:69:1;11132:407:10;1421:214:4;1559:68;;-1:-1:-1;;;;;11825:15:10;;;1559:68:4;;;11807:34:10;11877:15;;11857:18;;;11850:43;11909:18;;;11902:34;;;1532:96:4;;1552:5;;1582:27;;11719:18:10;;1559:68:4;11544:398:10;5328:653:4;5758:23;5784:69;5812:4;5784:69;;;;;;;;;;;;;;;;;5792:5;-1:-1:-1;;;;;5784:27:4;;;:69;;;;;:::i;:::-;5758:95;;5871:10;:17;5892:1;5871:22;:56;;;;5908:10;5897:30;;;;;;;;;;;;:::i;:::-;5863:111;;;;-1:-1:-1;;;5863:111:4;;12149:2:10;5863:111:4;;;12131:21:10;12188:2;12168:18;;;12161:30;12227:34;12207:18;;;12200:62;12298:12;12278:18;;;12271:40;12328:19;;5863:111:4;11947:406:10;4119:223:5;4252:12;4283:52;4305:6;4313:4;4319:1;4322:12;4283:21;:52::i;:::-;4276:59;4119:223;-1:-1:-1;;;;4119:223:5:o;5176:446::-;5341:12;5398:5;5373:21;:30;;5365:81;;;;-1:-1:-1;;;5365:81:5;;12560:2:10;5365:81:5;;;12542:21:10;12599:2;12579:18;;;12572:30;12638:34;12618:18;;;12611:62;12709:8;12689:18;;;12682:36;12735:19;;5365:81:5;12358:402:10;5365:81:5;5457:12;5471:23;5498:6;-1:-1:-1;;;;;5498:11:5;5517:5;5524:4;5498:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5456:73;;;;5546:69;5573:6;5581:7;5590:10;5602:12;5546:26;:69::i;:::-;5539:76;5176:446;-1:-1:-1;;;;;;;5176:446:5:o;7682:628::-;7862:12;7890:7;7886:418;;;7917:10;:17;7938:1;7917:22;7913:286;;-1:-1:-1;;;;;1702:19:7;;;8124:60:5;;;;-1:-1:-1;;;8124:60:5;;13514:2:10;8124:60:5;;;13496:21:10;13553:2;13533:18;;;13526:30;13592:31;13572:18;;;13565:59;13641:18;;8124:60:5;13312:353:10;8124:60:5;-1:-1:-1;8219:10:5;8212:17;;7886:418;8260:33;8268:10;8280:12;8991:17;;:21;8987:379;;9219:10;9213:17;9275:15;9262:10;9258:2;9254:19;9247:44;8987:379;9342:12;9335:20;;-1:-1:-1;;;9335:20:5;;;;;;;;:::i;14:184:10:-;-1:-1:-1;;;63:1:10;56:88;163:4;160:1;153:15;187:4;184:1;177:15;203:156;269:20;;329:4;318:16;;308:27;;298:55;;349:1;346;339:12;364:182;421:6;474:2;462:9;453:7;449:23;445:32;442:52;;;490:1;487;480:12;442:52;513:27;530:9;513:27;:::i;743:180::-;802:6;855:2;843:9;834:7;830:23;826:32;823:52;;;871:1;868;861:12;823:52;-1:-1:-1;894:23:10;;743:180;-1:-1:-1;743:180:10:o;1488:173::-;-1:-1:-1;;;;;1586:5:10;1582:54;1575:5;1572:65;1562:93;;1651:1;1648;1641:12;1666:519;1768:6;1776;1784;1837:2;1825:9;1816:7;1812:23;1808:32;1805:52;;;1853:1;1850;1843:12;1805:52;1892:9;1879:23;1911:50;1955:5;1911:50;:::i;:::-;1980:5;-1:-1:-1;2032:2:10;2017:18;;2004:32;;-1:-1:-1;2088:2:10;2073:18;;2060:32;2101:52;2060:32;2101:52;:::i;:::-;2172:7;2162:17;;;1666:519;;;;;:::o;2190:266::-;2249:6;2302:2;2290:9;2281:7;2277:23;2273:32;2270:52;;;2318:1;2315;2308:12;2270:52;2357:9;2344:23;2376:50;2420:5;2376:50;:::i;2906:184::-;-1:-1:-1;;;2955:1:10;2948:88;3055:4;3052:1;3045:15;3079:4;3076:1;3069:15;3095:253;3167:2;3161:9;3209:4;3197:17;;3244:18;3229:34;;3265:22;;;3226:62;3223:88;;;3291:18;;:::i;:::-;3327:2;3320:22;3095:253;:::o;3353:275::-;3424:2;3418:9;3489:2;3470:13;;-1:-1:-1;;3466:27:10;3454:40;;3524:18;3509:34;;3545:22;;;3506:62;3503:88;;;3571:18;;:::i;:::-;3607:2;3600:22;3353:275;;-1:-1:-1;3353:275:10:o;3633:1427::-;3723:6;3754:2;3797;3785:9;3776:7;3772:23;3768:32;3765:52;;;3813:1;3810;3803:12;3765:52;3853:9;3840:23;3882:18;3923:2;3915:6;3912:14;3909:34;;;3939:1;3936;3929:12;3909:34;3962:22;;;;4018:4;4000:16;;;3996:27;3993:47;;;4036:1;4033;4026:12;3993:47;4062:22;;:::i;:::-;4107:20;4124:2;4107:20;:::i;:::-;4100:5;4093:35;4160:29;4185:2;4181;4177:11;4160:29;:::i;:::-;4155:2;4148:5;4144:14;4137:53;4236:2;4232;4228:11;4215:25;4265:2;4255:8;4252:16;4249:36;;;4281:1;4278;4271:12;4249:36;4312:8;4308:2;4304:17;4294:27;;;4359:7;4352:4;4348:2;4344:13;4340:27;4330:55;;4381:1;4378;4371:12;4330:55;4417:2;4404:16;4439:2;4435;4432:10;4429:36;;;4445:18;;:::i;:::-;4491:2;4488:1;4484:10;4474:20;;4514:28;4538:2;4534;4530:11;4514:28;:::i;:::-;4576:15;;;4646:11;;;4642:20;;;4607:12;;;;4674:19;;;4671:39;;;4706:1;4703;4696:12;4671:39;4730:11;;;;4750:242;4766:6;4761:3;4758:15;4750:242;;;4848:3;4835:17;4820:32;;4865:52;4909:7;4865:52;:::i;:::-;4930:20;;;4783:12;;;;4970;;;;4750:242;;;5019:2;5008:14;;5001:29;-1:-1:-1;5012:5:10;;3633:1427;-1:-1:-1;;;;;;;3633:1427:10:o;5552:118::-;5638:5;5631:13;5624:21;5617:5;5614:32;5604:60;;5660:1;5657;5650:12;5675:311;5738:6;5746;5799:2;5787:9;5778:7;5774:23;5770:32;5767:52;;;5815:1;5812;5805:12;5767:52;5838:27;5855:9;5838:27;:::i;:::-;5828:37;;5915:2;5904:9;5900:18;5887:32;5928:28;5950:5;5928:28;:::i;:::-;5975:5;5965:15;;;5675:311;;;;;:::o;5991:586::-;6068:6;6076;6084;6137:2;6125:9;6116:7;6112:23;6108:32;6105:52;;;6153:1;6150;6143:12;6105:52;6192:9;6179:23;6211:50;6255:5;6211:50;:::i;:::-;6280:5;-1:-1:-1;6337:2:10;6322:18;;6309:32;6350:52;6309:32;6350:52;:::i;:::-;6421:7;-1:-1:-1;6480:2:10;6465:18;;6452:32;6493:52;6452:32;6493:52;:::i;7087:184::-;-1:-1:-1;;;7136:1:10;7129:88;7236:4;7233:1;7226:15;7260:4;7257:1;7250:15;7276:125;7341:9;;;7362:10;;;7359:36;;;7375:18;;:::i;:::-;7276:125;;;;:::o;7406:184::-;-1:-1:-1;;;7455:1:10;7448:88;7555:4;7552:1;7545:15;7579:4;7576:1;7569:15;7595:128;7662:9;;;7683:11;;;7680:37;;;7697:18;;:::i;8030:135::-;8069:3;8090:17;;;8087:43;;8110:18;;:::i;:::-;-1:-1:-1;8157:1:10;8146:13;;8030:135::o;9054:184::-;9124:6;9177:2;9165:9;9156:7;9152:23;9148:32;9145:52;;;9193:1;9190;9183:12;9145:52;-1:-1:-1;9216:16:10;;9054:184;-1:-1:-1;9054:184:10:o;9575:245::-;9642:6;9695:2;9683:9;9674:7;9670:23;9666:32;9663:52;;;9711:1;9708;9701:12;9663:52;9743:9;9737:16;9762:28;9784:5;9762:28;:::i;10593:184::-;-1:-1:-1;;;10642:1:10;10635:88;10742:4;10739:1;10732:15;10766:4;10763:1;10756:15;12765:250;12850:1;12860:113;12874:6;12871:1;12868:13;12860:113;;;12950:11;;;12944:18;12931:11;;;12924:39;12896:2;12889:10;12860:113;;;-1:-1:-1;;13007:1:10;12989:16;;12982:27;12765:250::o;13020:287::-;13149:3;13187:6;13181:13;13203:66;13262:6;13257:3;13250:4;13242:6;13238:17;13203:66;:::i;:::-;13285:16;;;;;13020:287;-1:-1:-1;;13020:287:10:o;13670:396::-;13819:2;13808:9;13801:21;13782:4;13851:6;13845:13;13894:6;13889:2;13878:9;13874:18;13867:34;13910:79;13982:6;13977:2;13966:9;13962:18;13957:2;13949:6;13945:15;13910:79;:::i;:::-;14050:2;14029:15;-1:-1:-1;;14025:29:10;14010:45;;;;14057:2;14006:54;;13670:396;-1:-1:-1;;13670:396:10:o
Swarm Source
ipfs://88f1db58e1108e18c2ab5c78579c038b913995f52e039e51c16be1237fbb15b0
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.