More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 45 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Rebalance | 18817127 | 263 days ago | IN | 0 ETH | 0.0086589 | ||||
Claim And Swap R... | 18788052 | 267 days ago | IN | 0 ETH | 0.05920626 | ||||
Rebalance | 18612504 | 292 days ago | IN | 0 ETH | 0.0720399 | ||||
Claim And Swap R... | 18588935 | 295 days ago | IN | 0 ETH | 0.05672647 | ||||
Rebalance | 18562490 | 299 days ago | IN | 0 ETH | 0.13725507 | ||||
Rebalance | 18511556 | 306 days ago | IN | 0 ETH | 0.06376637 | ||||
Claim And Swap R... | 18510579 | 306 days ago | IN | 0 ETH | 0.05177174 | ||||
Rebalance | 18461294 | 313 days ago | IN | 0 ETH | 0.04298306 | ||||
Claim And Swap R... | 18438876 | 316 days ago | IN | 0 ETH | 0.04414743 | ||||
Rebalance | 18411309 | 320 days ago | IN | 0 ETH | 0.0340647 | ||||
Rebalance | 18361251 | 327 days ago | IN | 0 ETH | 0.01668231 | ||||
Claim And Swap R... | 18360562 | 327 days ago | IN | 0 ETH | 0.01026045 | ||||
Rebalance | 18311233 | 334 days ago | IN | 0 ETH | 0.01654892 | ||||
Claim And Swap R... | 18288799 | 337 days ago | IN | 0 ETH | 0.01271908 | ||||
Rebalance | 18261150 | 341 days ago | IN | 0 ETH | 0.02496566 | ||||
Rebalance | 18211114 | 348 days ago | IN | 0 ETH | 0.02981517 | ||||
Claim And Swap R... | 18210731 | 348 days ago | IN | 0 ETH | 0.01654374 | ||||
Rebalance | 18161169 | 355 days ago | IN | 0 ETH | 0.03412953 | ||||
Claim And Swap R... | 18139563 | 358 days ago | IN | 0 ETH | 0.02193632 | ||||
Rebalance | 18111425 | 362 days ago | IN | 0 ETH | 0.03500844 | ||||
Rebalance | 18061427 | 369 days ago | IN | 0 ETH | 0.03500628 | ||||
Claim And Swap R... | 18060446 | 369 days ago | IN | 0 ETH | 0.02163525 | ||||
Rebalance | 18011452 | 376 days ago | IN | 0 ETH | 0.04626562 | ||||
Claim And Swap R... | 17989044 | 379 days ago | IN | 0 ETH | 0.07595442 | ||||
Rebalance | 17961412 | 383 days ago | IN | 0 ETH | 0.04274791 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
ConvexForFrax
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 500 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; import "vesper-pools/contracts/dependencies/openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "../../interfaces/convex/IConvexForFrax.sol"; import "../../strategies/curve/CurveBase.sol"; /** * @title Convex for Frax strategy * @dev This strategy only supports Curve deposits */ contract ConvexForFrax is CurveBase { using SafeERC20 for IERC20; IVaultRegistry public constant VAULT_REGISTRY = IVaultRegistry(0x569f5B842B5006eC17Be02B8b94510BA8e79FbCa); IConvexFraxPoolRegistry public constant POOL_REGISTRY = IConvexFraxPoolRegistry(0x41a5881c17185383e19Df6FA4EC158a6F4851A69); address public constant CVX = 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B; address public constant FXS = 0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0; /// @notice Frax Staking contract IFraxFarmERC20 public immutable fraxStaking; /// @notice Convex vault to interact with FRAX staking IStakingProxyConvex public immutable vault; /// @notice Convex Rewards contract IMultiReward public immutable rewards; /// @notice FRAX staking period /// @dev Uses the `lock_time_min` by default. Use `updateLockPeriod` to update it if needed. uint256 public lockPeriod; /// @notice Staking position ID bytes32 public kekId; /// @notice Next time where the withdraw will be available uint256 public unlockTime; /// @notice Emitted when `unlockTime` is updated event UnlockTimeUpdated(uint256 oldUnlockTime, uint256 newUnlockTime); constructor( address pool_, address crvPool_, PoolType curvePoolType_, address depositZap_, address crvToken_, uint256 crvSlippage_, address masterOracle_, address swapper_, uint256 collateralIdx_, uint256 convexPoolId_, string memory name_ ) CurveBase( pool_, crvPool_, curvePoolType_, depositZap_, crvToken_, crvSlippage_, masterOracle_, swapper_, collateralIdx_, name_ ) { (, address _stakingAddress, , address _reward, ) = POOL_REGISTRY.poolInfo(convexPoolId_); rewards = IMultiReward(_reward); vault = IStakingProxyConvex(VAULT_REGISTRY.createVault(convexPoolId_)); require(vault.curveLpToken() == address(crvLp), "incorrect-lp-token"); fraxStaking = IFraxFarmERC20(_stakingAddress); lockPeriod = fraxStaking.lock_time_min(); rewardTokens = _getRewardTokens(); } function lpBalanceStaked() public view override returns (uint256 _total) { // Note: No need to specify which position here because we'll always have one open position at the same time // because of the open position is deleted when `vault.withdrawLockedAndUnwrap(kekId)` is called _total = fraxStaking.lockedLiquidityOf(address(vault)); } function _approveToken(uint256 amount_) internal virtual override { super._approveToken(amount_); crvLp.safeApprove(address(vault), amount_); } /// @dev Return values are not being used hence returning 0 function _claimRewards() internal override returns (address, uint256) { // solhint-disable-next-line no-empty-blocks try vault.getReward() {} catch { // It may fail if reward collection is paused on FRAX side // See more: https://github.com/convex-eth/frax-cvx-platform/blob/01855f4f82729b49cbed0b5fab37bdefe9fdb736/contracts/contracts/StakingProxyConvex.sol#L222-L225 vault.getReward(false); } return (address(0), 0); } /// @notice Get reward tokens function _getRewardTokens() internal view override returns (address[] memory _rewardTokens) { uint256 _extraRewardCount; uint256 _length = rewards.rewardTokenLength(); for (uint256 i; i < _length; i++) { address _rewardToken = rewards.rewardTokens(i); // Some pool has CVX as extra rewards but other do not. CVX still reward token if (_rewardToken != CRV && _rewardToken != CVX && _rewardToken != FXS) { _extraRewardCount++; } } _rewardTokens = new address[](_extraRewardCount + 3); _rewardTokens[0] = CRV; _rewardTokens[1] = CVX; _rewardTokens[2] = FXS; uint256 _nextIdx = 3; for (uint256 i; i < _length; i++) { address _rewardToken = rewards.rewardTokens(i); // CRV and CVX already added in array if (_rewardToken != CRV && _rewardToken != CVX && _rewardToken != FXS) { _rewardTokens[_nextIdx++] = _rewardToken; } } } /** * @notice Stake Curve-LP token * @dev Stake to the current position if there is any */ function _stakeAllLp() internal virtual override { uint256 _balance = crvLp.balanceOf(address(this)); if (_balance > 0) { if (kekId != bytes32(0)) { // if there is an active position, lock more vault.lockAdditionalCurveLp(kekId, _balance); } else { // otherwise create a new position kekId = vault.stakeLockedCurveLp(_balance, lockPeriod); unlockTime = block.timestamp + lockPeriod; } } } /** * @notice Unstake all LPs * @dev This function is called by `_beforeMigration()` hook * @dev `withdrawLockedAndUnwrap` destroys current position * Should claim rewards that will be swept later */ function _unstakeAllLp() internal override { require(block.timestamp >= unlockTime, "unlock-time-didnt-pass"); vault.withdrawLockedAndUnwrap(kekId); kekId = 0x0; } /** * @notice Unstake LPs * @dev Unstake all because Convex-FRAX doesn't support partial unlocks */ function _unstakeLp(uint256 _amount) internal override { if (_amount > 0) { _unstakeAllLp(); } } /// @notice Update `lockPeriod` param /// @dev To be used if the `lock_time_min` value changes or we want to increase it function updateLockPeriod(uint256 newLockPeriod_) external onlyGovernor { require(newLockPeriod_ >= fraxStaking.lock_time_min(), "period-lt-min"); emit UnlockTimeUpdated(lockPeriod, newLockPeriod_); lockPeriod = newLockPeriod_; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; interface IStrategy { function rebalance() external returns (uint256 _profit, uint256 _loss, uint256 _payback); function sweep(address _fromToken) external; function withdraw(uint256 _amount) external; function feeCollector() external view returns (address); function isReservedToken(address _token) external view returns (bool); function keepers() external view returns (address[] memory); function migrate(address _newStrategy) external; function token() external view returns (address); function pool() external view returns (address); // solhint-disable-next-line func-name-mixedcase function VERSION() external view returns (string memory); function collateral() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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 `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool); /** * @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); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length 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)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @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 * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 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://diligence.consensys.net/posts/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.5.11/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"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (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 functionCall(target, data, "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"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(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) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(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) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // 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 // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /* * @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 Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @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, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCast { /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits. */ function toUint8(uint256 value) internal pure returns (uint8) { require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128) { require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\'t fit in 128 bits"); return int128(value); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64) { require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\'t fit in 64 bits"); return int64(value); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32) { require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\'t fit in 32 bits"); return int32(value); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16) { require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\'t fit in 16 bits"); return int16(value); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits. * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8) { require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\'t fit in 8 bits"); return int8(value); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { require(value < 2**255, "SafeCast: value doesn't fit in an int256"); return int256(value); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { return _values(set._inner); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; /** * @notice Governable interface */ interface IGovernable { function governor() external view returns (address _governor); function transferGovernorship(address _proposedGovernor) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; /** * @notice Pausable interface */ interface IPausable { function paused() external view returns (bool); function stopEverything() external view returns (bool); function pause() external; function unpause() external; function shutdown() external; function open() external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; import "../../dependencies/openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "./IGovernable.sol"; import "./IPausable.sol"; interface IVesperPool is IGovernable, IPausable, IERC20Metadata { function calculateUniversalFee(uint256 profit_) external view returns (uint256 _fee); function deposit(uint256 collateralAmount_) external; function excessDebt(address strategy_) external view returns (uint256); function poolAccountant() external view returns (address); function poolRewards() external view returns (address); function reportEarning(uint256 profit_, uint256 loss_, uint256 payback_) external; function reportLoss(uint256 loss_) external; function sweepERC20(address fromToken_) external; function withdraw(uint256 share_) external; function keepers() external view returns (address[] memory); function isKeeper(address address_) external view returns (bool); function maintainers() external view returns (address[] memory); function isMaintainer(address address_) external view returns (bool); function pricePerShare() external view returns (uint256); function strategy( address strategy_ ) external view returns ( bool _active, uint256 _interestFee, // Obsolete uint256 _debtRate, // Obsolete uint256 _lastRebalance, uint256 _totalDebt, uint256 _totalLoss, uint256 _totalProfit, uint256 _debtRatio, uint256 _externalDepositFee ); function token() external view returns (IERC20); function tokensHere() external view returns (uint256); function totalDebtOf(address strategy_) external view returns (uint256); function totalValue() external view returns (uint256); function totalDebt() external view returns (uint256); }
// SPDX-License-Identifier: MIT // solhint-disable var-name-mixedcase // solhint-disable func-name-mixedcase pragma solidity 0.8.9; interface IConvexFraxPoolRegistry { function poolInfo( uint256 ) external view returns ( address implementation, address stakingAddress, address stakingToken, address rewardsAddress, uint8 active ); } interface IVaultRegistry { function createVault(uint256 _pid) external returns (address); } interface IProxyVault { function initialize( address _owner, address _stakingAddress, address _stakingToken, address _rewardsAddress ) external; function usingProxy() external returns (address); function owner() external returns (address); function stakingAddress() external returns (address); function rewards() external returns (address); function getReward() external; function getReward(bool _claim) external; function getReward(bool _claim, address[] calldata _rewardTokenList) external; function earned() external view returns (address[] memory token_addresses, uint256[] memory total_earned); } interface IStakingProxyBase is IProxyVault { //farming contract function stakingAddress() external view returns (address); //farming token function stakingToken() external view returns (address); function vaultVersion() external pure returns (uint256); } interface IStakingProxyConvex is IStakingProxyBase { function curveLpToken() external view returns (address); function convexDepositToken() external view returns (address); //create a new locked state of _secs timelength with a Curve LP token function stakeLockedCurveLp(uint256 _liquidity, uint256 _secs) external returns (bytes32 kek_id); //create a new locked state of _secs timelength with a Convex deposit token function stakeLockedConvexToken(uint256 _liquidity, uint256 _secs) external returns (bytes32 kek_id); //create a new locked state of _secs timelength function stakeLocked(uint256 _liquidity, uint256 _secs) external returns (bytes32 kek_id); //add to a current lock function lockAdditional(bytes32 _kek_id, uint256 _addl_liq) external; //add to a current lock function lockAdditionalCurveLp(bytes32 _kek_id, uint256 _addl_liq) external; //add to a current lock function lockAdditionalConvexToken(bytes32 _kek_id, uint256 _addl_liq) external; // Extends the lock of an existing stake function lockLonger(bytes32 _kek_id, uint256 new_ending_ts) external; //withdraw a staked position //frax farm transfers first before updating farm state so will checkpoint during transfer function withdrawLocked(bytes32 _kek_id) external; //withdraw a staked position //frax farm transfers first before updating farm state so will checkpoint during transfer function withdrawLockedAndUnwrap(bytes32 _kek_id) external; //helper function to combine earned tokens on staking contract and any tokens that are on this vault function earned() external view override returns (address[] memory token_addresses, uint256[] memory total_earned); } interface IFraxFarmERC20 { event StakeLocked(address indexed user, uint256 amount, uint256 secs, bytes32 kek_id, address source_address); struct LockedStake { bytes32 kek_id; uint256 start_timestamp; uint256 liquidity; uint256 ending_timestamp; uint256 lock_multiplier; // 6 decimals of precision. 1x = 1000000 } function owner() external view returns (address); function stakingToken() external view returns (address); function fraxPerLPToken() external view returns (uint256); function calcCurCombinedWeight( address account ) external view returns (uint256 old_combined_weight, uint256 new_vefxs_multiplier, uint256 new_combined_weight); function lockedStakesOf(address account) external view returns (LockedStake[] memory); function lockedStakesOfLength(address account) external view returns (uint256); function lockAdditional(bytes32 kek_id, uint256 addl_liq) external; function lockLonger(bytes32 kek_id, uint256 new_ending_ts) external; function stakeLocked(uint256 liquidity, uint256 secs) external returns (bytes32); function withdrawLocked(bytes32 kek_id, address destination_address) external returns (uint256); function periodFinish() external view returns (uint256); function getAllRewardTokens() external view returns (address[] memory); function earned(address account) external view returns (uint256[] memory new_earned); function totalLiquidityLocked() external view returns (uint256); function lockedLiquidityOf(address account) external view returns (uint256); function totalCombinedWeight() external view returns (uint256); function combinedWeightOf(address account) external view returns (uint256); function lockMultiplier(uint256 secs) external view returns (uint256); function lock_time_min() external view returns (uint256); function rewardRates(uint256 token_idx) external view returns (uint256 rwd_rate); function userStakedFrax(address account) external view returns (uint256); function proxyStakedFrax(address proxy_address) external view returns (uint256); function maxLPForMaxBoost(address account) external view returns (uint256); function minVeFXSForMaxBoost(address account) external view returns (uint256); function minVeFXSForMaxBoostProxy(address proxy_address) external view returns (uint256); function veFXSMultiplier(address account) external view returns (uint256 vefxs_multiplier); function toggleValidVeFXSProxy(address proxy_address) external; function proxyToggleStaker(address staker_address) external; function stakerSetVeFXSProxy(address proxy_address) external; function getReward(address destination_address) external returns (uint256[] memory); function vefxs_max_multiplier() external view returns (uint256); function vefxs_boost_scale_factor() external view returns (uint256); function vefxs_per_frax_for_max_boost() external view returns (uint256); function getProxyFor(address addr) external view returns (address); function sync() external; } interface IMultiReward { function poolId() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function rewardPerToken() external view returns (uint256); function rewardTokenLength() external view returns (uint256); function rewardTokens(uint256) external view returns (address); function rewards(address) external view returns (uint256); function userRewardPerTokenPaid(address) external view returns (uint256); }
// SPDX-License-Identifier: MIT /* solhint-disable */ pragma solidity 0.8.9; interface IAddressProvider { function get_registry() external view returns (address); function get_address(uint256 i) external view returns (address); }
// SPDX-License-Identifier: MIT /* solhint-disable */ pragma solidity 0.8.9; interface IDeposit2x { function add_liquidity(uint256[2] memory _amounts, uint256 _min_mint_amount) external; function calc_withdraw_one_coin(uint256 _token_amount, int128 i) external view returns (uint256); function remove_liquidity_one_coin(uint256 _token_amount, int128 i, uint256 _min_amount) external; } interface IDeposit3x { function add_liquidity(uint256[3] memory _amounts, uint256 _min_mint_amount) external; function calc_withdraw_one_coin(uint256 _token_amount, int128 i) external view returns (uint256); function remove_liquidity_one_coin(uint256 _token_amount, int128 i, uint256 _min_amount) external; } interface IDeposit4x { function add_liquidity(uint256[4] memory _amounts, uint256 _min_mint_amount) external payable; function remove_liquidity(uint256 _amount, uint256[4] memory _min_amounts) external; function remove_liquidity_one_coin(uint256 _token_amount, int128 i, uint256 _min_amount) external; function calc_withdraw_one_coin(uint256 _token_amount, int128 i) external view returns (uint256); function calc_token_amount(uint256[4] memory _amounts, bool is_deposit) external view returns (uint256); function token() external view returns (address); }
// SPDX-License-Identifier: MIT /* solhint-disable */ pragma solidity 0.8.9; interface IDepositZap { function remove_liquidity_one_coin(address _pool, uint256 _burn_amount, int128 i, uint256 _min_amount) external; function calc_withdraw_one_coin(address _pool, uint256 _token_amount, int128 i) external view returns (uint256); } interface IDepositZap3x is IDepositZap { function calc_token_amount( address _pool, uint256[3] memory _amounts, bool is_deposit ) external view returns (uint256); function add_liquidity( address _pool, uint256[3] memory _deposit_amounts, uint256 _min_mint_amount ) external payable; function remove_liquidity(address _pool, uint256 _burn_amount, uint256[3] memory _min_amounts) external; } interface IDepositZap4x is IDepositZap { function calc_token_amount( address _pool, uint256[4] memory _amounts, bool is_deposit ) external view returns (uint256); function add_liquidity(address _pool, uint256[4] memory _amounts, uint256 _min_mint_amount) external payable; function remove_liquidity(address _pool, uint256 _amount, uint256[4] memory _min_amounts) external; }
// SPDX-License-Identifier: MIT /* solhint-disable */ pragma solidity 0.8.9; import "vesper-pools/contracts/dependencies/openzeppelin/contracts/token/ERC20/IERC20.sol"; interface ILiquidityGauge { function lp_token() external view returns (address); function integrate_fraction(address addr) external view returns (uint256); function claimable_tokens(address addr) external returns (uint256); function user_checkpoint(address addr) external returns (bool); function deposit(uint256 _value) external; function deposit(uint256 _value, address addr) external; function withdraw(uint256 _value) external; } interface ILiquidityGaugeReward is ILiquidityGauge { function reward_contract() external view returns (address); function rewarded_token() external view returns (address); } interface ILiquidityGaugeV2 is IERC20, ILiquidityGauge { function claim_rewards(address addr) external; function claim_rewards() external; function claimable_reward(address, address) external returns (uint256); function reward_integral(address) external view returns (uint256); function reward_integral_for(address, address) external view returns (uint256); function reward_count() external view returns (uint256); function reward_tokens(uint256 _i) external view returns (address); } interface ILiquidityGaugeV3 is ILiquidityGaugeV2 { function claimable_reward(address addr, address token) external view override returns (uint256); function claimable_reward_write(address addr, address token) external returns (uint256); } /* solhint-enable */
// SPDX-License-Identifier: MIT /* solhint-disable */ pragma solidity 0.8.9; interface ILiquidityGaugeFactory { function get_gauge_from_lp_token(address lp_token) external view returns (address); function is_valid_gauge(address _gauge) external view returns (bool); function mint(address gauge_addr) external; } /* solhint-enable */
// SPDX-License-Identifier: MIT /* solhint-disable func-name-mixedcase*/ pragma solidity 0.8.9; interface IMetapoolFactory { function get_underlying_coins(address pool) external view returns (address[8] memory); function get_underlying_decimals(address pool) external view returns (uint256[8] memory); function get_coins(address pool) external view returns (address[4] memory); function get_n_coins(address pool) external view returns (uint256); function get_meta_n_coins(address pool) external view returns (uint256[2] memory); function get_decimals(address pool) external view returns (uint256[4] memory); function get_gauge(address pool) external view returns (address); function is_meta(address pool) external view returns (bool); }
// SPDX-License-Identifier: MIT /* solhint-disable */ pragma solidity 0.8.9; interface IRegistry { function get_pool_from_lp_token() external view returns (address); function get_lp_token(address pool) external view returns (address); function get_n_coins(address pool) external view returns (uint256[2] memory); function get_underlying_coins(address pool) external view returns (address[8] memory); function get_underlying_decimals(address pool) external view returns (uint256[8] memory); function get_gauges(address pool) external view returns (address[10] memory); }
// SPDX-License-Identifier: MIT /* solhint-disable */ pragma solidity 0.8.9; // Not a complete interface, but should have what we need interface IStableSwap { function coins(uint256 i) external view returns (address); function fee() external view returns (uint256); // fee * 1e10 function lp_token() external view returns (address); function A() external view returns (uint256); function A_precise() external view returns (uint256); function balances(uint256 i) external view returns (uint256); function get_virtual_price() external view returns (uint256); function get_dy(int128 i, int128 j, uint256 dx) external view returns (uint256); function get_dy_underlying(int128 i, int128 j, uint256 dx) external view returns (uint256); function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) external returns (uint256); function calc_withdraw_one_coin(uint256 _token_amount, int128 i) external view returns (uint256); function remove_liquidity_one_coin(uint256 _token_amount, int128 i, uint256 _min_amount) external; } interface IStableSwapV2 { function coins(int128 i) external view returns (address); } interface IStableSwapUnderlying is IStableSwap { function underlying_coins(uint256 i) external view returns (address); function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy) external; function remove_liquidity_one_coin( uint256 _token_amount, int128 i, uint256 _min_amount, bool _use_underlying ) external; } interface IStableSwap2x is IStableSwap { function calc_token_amount(uint256[2] memory _amounts, bool is_deposit) external view returns (uint256); function add_liquidity(uint256[2] memory _amounts, uint256 _min_mint_amount) external payable; function remove_liquidity(uint256 _amount, uint256[2] memory _min_amounts) external; function remove_liquidity_imbalance( uint256[2] memory _amounts, uint256 _max_burn_amount ) external returns (uint256); } interface IStableSwap3x is IStableSwap { function calc_token_amount(uint256[3] memory _amounts, bool is_deposit) external view returns (uint256); function add_liquidity(uint256[3] memory _amounts, uint256 _min_mint_amount) external payable; function remove_liquidity(uint256 _amount, uint256[3] memory _min_amounts) external; function remove_liquidity_imbalance( uint256[3] memory _amounts, uint256 _max_burn_amount ) external returns (uint256); } interface IStableSwap4x is IStableSwap { function calc_token_amount(uint256[4] memory _amounts, bool is_deposit) external view returns (uint256); function add_liquidity(uint256[4] memory _amounts, uint256 _min_mint_amount) external payable; function remove_liquidity(uint256 _amount, uint256[4] memory _min_amounts) external; function remove_liquidity_imbalance( uint256[4] memory _amounts, uint256 _max_burn_amount ) external returns (uint256); } interface IStableSwap2xUnderlying is IStableSwap2x, IStableSwapUnderlying { function add_liquidity(uint256[2] calldata amounts, uint256 min_mint_amount, bool use_underlying) external payable; function remove_liquidity_imbalance( uint256[2] calldata amounts, uint256 max_burn_amount, bool use_underlying ) external; function remove_liquidity(uint256 amount, uint256[2] calldata min_amounts, bool use_underlying) external; } interface IStableSwap3xUnderlying is IStableSwap3x, IStableSwapUnderlying { function add_liquidity(uint256[3] calldata amounts, uint256 min_mint_amount, bool use_underlying) external payable; function remove_liquidity_imbalance( uint256[3] calldata amounts, uint256 max_burn_amount, bool use_underlying ) external; function remove_liquidity(uint256 amount, uint256[3] calldata min_amounts, bool use_underlying) external; } interface IStableSwap4xUnderlying is IStableSwap4x, IStableSwapUnderlying { function add_liquidity(uint256[4] calldata amounts, uint256 min_mint_amount, bool use_underlying) external payable; function remove_liquidity_imbalance( uint256[4] calldata amounts, uint256 max_burn_amount, bool use_underlying ) external; function remove_liquidity(uint256 amount, uint256[4] calldata min_amounts, bool use_underlying) external; } /* solhint-enable */
// SPDX-License-Identifier: MIT /* solhint-disable */ pragma solidity 0.8.9; // Not a complete interface, but should have what we need interface ITokenMinter { function minted(address arg0, address arg1) external view returns (uint256); function mint(address gauge_addr) external; } /* solhint-enable */
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; interface IMasterOracle { function getPriceInUsd(address token_) external view returns (uint256 _priceInUsd); function quote(address tokenIn_, address tokenOut_, uint256 amountIn_) external view returns (uint256 _amountOut); function quoteTokenToUsd(address token_, uint256 amountIn_) external view returns (uint256 amountOut_); function quoteUsdToToken(address token_, uint256 amountIn_) external view returns (uint256 _amountOut); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; /** * @notice Routed Swapper interface * @dev This contract doesn't support native coins (e.g. ETH, AVAX, MATIC, etc) use wrapper tokens instead */ interface IRoutedSwapper { /** * @notice The list of supported DEXes * @dev This function is gas intensive */ function getAllExchanges() external view returns (address[] memory); /** * @notice Get *spot* quote * It will return the swap amount based on the current reserves of the best pair/path found (i.e. spot price). * @dev It shouldn't be used as oracle!!! */ function getAmountIn(address tokenIn_, address tokenOut_, uint256 amountOut_) external returns (uint256 _amountIn); /** * @notice Get *spot* quote * It will return the swap amount based on the current reserves of the best pair/path found (i.e. spot price). * @dev It shouldn't be used as oracle!!! */ function getAmountOut(address tokenIn_, address tokenOut_, uint256 amountIn_) external returns (uint256 _amountOut); /** * @notice Perform an exact input swap - will revert if there is no default routing */ function swapExactInput( address tokenIn_, address tokenOut_, uint256 amountIn_, uint256 amountOutMin_, address _receiver ) external returns (uint256 _amountOut); /** * @notice Perform an exact output swap - will revert if there is no default routing */ function swapExactOutput( address tokenIn_, address tokenOut_, uint256 amountOut_, uint256 amountInMax_, address receiver_ ) external returns (uint256 _amountIn); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; import "vesper-pools/contracts/dependencies/openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "vesper-pools/contracts/dependencies/openzeppelin/contracts/utils/math/SafeCast.sol"; import "vesper-pools/contracts/dependencies/openzeppelin/contracts/utils/math/Math.sol"; import "../../interfaces/curve/IDeposit.sol"; import "../../interfaces/curve/IDepositZap.sol"; import "../../interfaces/curve/IStableSwap.sol"; import "../../interfaces/curve/ILiquidityGauge.sol"; import "../../interfaces/curve/ITokenMinter.sol"; import "../../interfaces/curve/IMetapoolFactory.sol"; import "../../interfaces/curve/IRegistry.sol"; import "../../interfaces/curve/IAddressProvider.sol"; import "../../interfaces/curve/ILiquidityGaugeFactory.sol"; import "../../interfaces/one-oracle/IMasterOracle.sol"; import "../Strategy.sol"; /// @title Base contract for Curve-related strategies abstract contract CurveBase is Strategy { using SafeERC20 for IERC20; enum PoolType { PLAIN_2_POOL, PLAIN_3_POOL, PLAIN_4_POOL, LENDING_2_POOL, LENDING_3_POOL, LENDING_4_POOL, META_3_POOL, META_4_POOL } string public constant VERSION = "5.1.0"; uint256 internal constant MAX_BPS = 10_000; ITokenMinter public constant CRV_MINTER = ITokenMinter(0xd061D61a4d941c39E5453435B6345Dc261C2fcE0); // This contract only exists on mainnet ILiquidityGaugeFactory public constant GAUGE_FACTORY = ILiquidityGaugeFactory(0xabC000d88f23Bb45525E447528DBF656A9D55bf5); // Act as CRV_MINTER on side chains IAddressProvider public constant ADDRESS_PROVIDER = IAddressProvider(0x0000000022D53366457F9d5E68Ec105046FC4383); // Same address to all chains uint256 private constant FACTORY_ADDRESS_ID = 3; // solhint-disable-next-line var-name-mixedcase address public immutable CRV; IERC20 public immutable crvLp; // Note: Same as `receiptToken` but using this in order to save gas since it's `immutable` and `receiptToken` isn't address public immutable crvPool; ILiquidityGaugeV2 public immutable crvGauge; uint256 public immutable collateralIdx; address internal immutable depositZap; PoolType public immutable curvePoolType; bool private immutable isFactoryPool; // solhint-disable-next-line var-name-mixedcase string public NAME; uint256 public crvSlippage; IMasterOracle public masterOracle; address[] public rewardTokens; event CrvSlippageUpdated(uint256 oldCrvSlippage, uint256 newCrvSlippage); event MasterOracleUpdated(IMasterOracle oldMasterOracle, IMasterOracle newMasterOracle); constructor( address pool_, address crvPool_, PoolType curvePoolType_, address depositZap_, address crvToken_, uint256 crvSlippage_, address masterOracle_, address swapper_, uint256 collateralIdx_, string memory name_ ) Strategy(pool_, swapper_, address(0)) { require(crvToken_ != address(0), "crv-token-is-null"); address _crvGauge; IRegistry _registry = IRegistry(ADDRESS_PROVIDER.get_registry()); address _crvLp = _registry.get_lp_token(crvPool_); if (_crvLp != address(0)) { // Get data from Registry contract require(collateralIdx_ < _registry.get_n_coins(crvPool_)[1], "invalid-collateral"); _verifyCollateral(_registry.get_underlying_coins(crvPool_)[collateralIdx_]); _crvGauge = _registry.get_gauges(crvPool_)[0]; } else { // Get data from Factory contract IMetapoolFactory _factory = IMetapoolFactory(ADDRESS_PROVIDER.get_address(FACTORY_ADDRESS_ID)); if (_factory.is_meta(crvPool_)) { require(collateralIdx_ < _factory.get_meta_n_coins(crvPool_)[1], "invalid-collateral"); _verifyCollateral(_factory.get_underlying_coins(crvPool_)[collateralIdx_]); } else { require(collateralIdx_ < _factory.get_n_coins(crvPool_), "invalid-collateral"); _verifyCollateral(_factory.get_coins(crvPool_)[collateralIdx_]); } _crvLp = crvPool_; _crvGauge = _factory.get_gauge(crvPool_); } require(crvPool_ != address(0), "pool-is-null"); require(_crvLp != address(0), "lp-is-null"); if (_crvGauge == address(0)) { _crvGauge = GAUGE_FACTORY.get_gauge_from_lp_token(_crvLp); } require(_crvGauge != address(0), "gauge-is-null"); CRV = crvToken_; crvPool = crvPool_; crvLp = IERC20(_crvLp); crvGauge = ILiquidityGaugeV2(_crvGauge); crvSlippage = crvSlippage_; receiptToken = _crvLp; collateralIdx = collateralIdx_; curvePoolType = curvePoolType_; isFactoryPool = _crvLp == crvPool_; depositZap = depositZap_; masterOracle = IMasterOracle(masterOracle_); NAME = name_; } function getRewardTokens() external view returns (address[] memory) { return rewardTokens; } /// @dev Check whether given token is reserved or not. Reserved tokens are not allowed to sweep. function isReservedToken(address token_) public view override returns (bool) { return token_ == address(crvLp) || token_ == address(collateralToken); } // Gets LP value not staked in gauge function lpBalanceHere() public view virtual returns (uint256 _lpHere) { _lpHere = crvLp.balanceOf(address(this)); } function lpBalanceHereAndStaked() public view virtual returns (uint256 _lpHereAndStaked) { _lpHereAndStaked = crvLp.balanceOf(address(this)) + lpBalanceStaked(); } function lpBalanceStaked() public view virtual returns (uint256 _lpStaked) { _lpStaked = crvGauge.balanceOf(address(this)); } /// @notice Returns collateral balance + collateral deposited to curve function tvl() external view override returns (uint256) { return collateralToken.balanceOf(address(this)) + _quoteLpToCoin(lpBalanceHereAndStaked(), SafeCast.toInt128(int256(collateralIdx))); } function _approveToken(uint256 amount_) internal virtual override { super._approveToken(amount_); address _swapper = address(swapper); collateralToken.safeApprove(crvPool, amount_); collateralToken.safeApprove(_swapper, amount_); uint256 _rewardTokensLength = rewardTokens.length; for (uint256 i; i < _rewardTokensLength; ++i) { IERC20(rewardTokens[i]).safeApprove(_swapper, amount_); } crvLp.safeApprove(address(crvGauge), amount_); if (depositZap != address(0)) { collateralToken.safeApprove(depositZap, amount_); crvLp.safeApprove(depositZap, amount_); } } /// @notice Unstake LP tokens in order to transfer to the new strategy function _beforeMigration(address newStrategy_) internal override { require(IStrategy(newStrategy_).collateral() == address(collateralToken), "wrong-collateral-token"); require(IStrategy(newStrategy_).token() == address(crvLp), "wrong-receipt-token"); _unstakeAllLp(); } function _calculateAmountOutMin( address tokenIn_, address tokenOut_, uint256 amountIn_ ) private view returns (uint256 _amountOutMin) { _amountOutMin = (masterOracle.quote(tokenIn_, tokenOut_, amountIn_) * (MAX_BPS - crvSlippage)) / MAX_BPS; } /** * @dev Curve pool may have more than one reward token. */ function _claimAndSwapRewards() internal virtual override { _claimRewards(); uint256 _rewardTokensLength = rewardTokens.length; for (uint256 i; i < _rewardTokensLength; ++i) { address _rewardToken = rewardTokens[i]; uint256 _amountIn = IERC20(_rewardToken).balanceOf(address(this)); if (_amountIn > 0) { _safeSwapExactInput(_rewardToken, address(collateralToken), _amountIn); } } } /// @dev Return values are not being used hence returning 0 function _claimRewards() internal virtual override returns (address, uint256) { if (block.chainid == 1) { CRV_MINTER.mint(address(crvGauge)); } else if (GAUGE_FACTORY.is_valid_gauge(address(crvGauge))) { // On side chain gauge factory can mint CRV reward but only for valid gauge. GAUGE_FACTORY.mint(address(crvGauge)); } // solhint-disable-next-line no-empty-blocks try crvGauge.claim_rewards() {} catch { // This call may fail in some scenarios // e.g. 3Crv gauge doesn't have such function } return (address(0), 0); } function _deposit() internal { _depositToCurve(collateralToken.balanceOf(address(this))); _stakeAllLp(); } function _depositTo2PlainPool(uint256 coinAmountIn_, uint256 lpAmountOutMin_, bool useEth_) private { uint256[2] memory _depositAmounts; _depositAmounts[collateralIdx] = coinAmountIn_; IStableSwap2x(crvPool).add_liquidity{value: useEth_ ? coinAmountIn_ : 0}(_depositAmounts, lpAmountOutMin_); } function _depositTo2LendingPool(uint256 coinAmountIn_, uint256 lpAmountOutMin_, bool useEth_) private { uint256[2] memory _depositAmounts; _depositAmounts[collateralIdx] = coinAmountIn_; // Note: Using use_underlying = true to deposit underlying instead of IB token IStableSwap2xUnderlying(crvPool).add_liquidity{value: useEth_ ? coinAmountIn_ : 0}( _depositAmounts, lpAmountOutMin_, true ); } function _depositTo3PlainPool(uint256 coinAmountIn_, uint256 lpAmountOutMin_, bool useEth_) private { uint256[3] memory _depositAmounts; _depositAmounts[collateralIdx] = coinAmountIn_; IStableSwap3x(crvPool).add_liquidity{value: useEth_ ? coinAmountIn_ : 0}(_depositAmounts, lpAmountOutMin_); } function _depositTo3LendingPool(uint256 coinAmountIn_, uint256 lpAmountOutMin_, bool useEth_) private { uint256[3] memory _depositAmounts; _depositAmounts[collateralIdx] = coinAmountIn_; // Note: Using use_underlying = true to deposit underlying instead of IB token IStableSwap3xUnderlying(crvPool).add_liquidity{value: useEth_ ? coinAmountIn_ : 0}( _depositAmounts, lpAmountOutMin_, true ); } function _depositTo4PlainOrMetaPool(uint256 coinAmountIn_, uint256 lpAmountOutMin_, bool useEth_) private { uint256[4] memory _depositAmounts; _depositAmounts[collateralIdx] = coinAmountIn_; IDeposit4x(depositZap).add_liquidity{value: useEth_ ? coinAmountIn_ : 0}(_depositAmounts, lpAmountOutMin_); } function _depositTo3FactoryMetaPool(uint256 coinAmountIn_, uint256 lpAmountOutMin_, bool useEth_) private { uint256[3] memory _depositAmounts; _depositAmounts[collateralIdx] = coinAmountIn_; // Note: The function below won't return a reason when reverting due to slippage IDepositZap3x(depositZap).add_liquidity{value: useEth_ ? coinAmountIn_ : 0}( address(crvPool), _depositAmounts, lpAmountOutMin_ ); } function _depositTo4FactoryMetaPool(uint256 coinAmountIn_, uint256 lpAmountOutMin_, bool useEth_) private { uint256[4] memory _depositAmounts; _depositAmounts[collateralIdx] = coinAmountIn_; // Note: The function below won't return a reason when reverting due to slippage IDepositZap4x(depositZap).add_liquidity{value: useEth_ ? coinAmountIn_ : 0}( address(crvPool), _depositAmounts, lpAmountOutMin_ ); } function _depositToCurve(uint256 coinAmountIn_) internal virtual { _depositToCurve(coinAmountIn_, false); } function _depositToCurve(uint256 coinAmountIn_, bool useEth_) internal virtual { if (coinAmountIn_ == 0) { return; } uint256 _lpAmountOutMin = _calculateAmountOutMin(address(collateralToken), address(crvLp), coinAmountIn_); if (curvePoolType == PoolType.PLAIN_2_POOL) { return _depositTo2PlainPool(coinAmountIn_, _lpAmountOutMin, useEth_); } if (curvePoolType == PoolType.LENDING_2_POOL) { return _depositTo2LendingPool(coinAmountIn_, _lpAmountOutMin, useEth_); } if (curvePoolType == PoolType.PLAIN_3_POOL) { return _depositTo3PlainPool(coinAmountIn_, _lpAmountOutMin, useEth_); } if (curvePoolType == PoolType.LENDING_3_POOL) { return _depositTo3LendingPool(coinAmountIn_, _lpAmountOutMin, useEth_); } if (curvePoolType == PoolType.PLAIN_4_POOL) { return _depositTo4PlainOrMetaPool(coinAmountIn_, _lpAmountOutMin, useEth_); } if (curvePoolType == PoolType.META_3_POOL) { return _depositTo3FactoryMetaPool(coinAmountIn_, _lpAmountOutMin, useEth_); } if (curvePoolType == PoolType.META_4_POOL) { if (isFactoryPool) { return _depositTo4FactoryMetaPool(coinAmountIn_, _lpAmountOutMin, useEth_); } return _depositTo4PlainOrMetaPool(coinAmountIn_, _lpAmountOutMin, useEth_); } revert("deposit-to-curve-failed"); } function _generateReport() internal virtual returns (uint256 _profit, uint256 _loss, uint256 _payback) { uint256 _excessDebt = IVesperPool(pool).excessDebt(address(this)); uint256 _strategyDebt = IVesperPool(pool).totalDebtOf(address(this)); int128 _i = SafeCast.toInt128(int256(collateralIdx)); uint256 _lpHere = lpBalanceHere(); uint256 _totalLp = _lpHere + lpBalanceStaked(); uint256 _collateralInCurve = _quoteLpToCoin(_totalLp, _i); uint256 _collateralHere = collateralToken.balanceOf(address(this)); uint256 _totalCollateral = _collateralHere + _collateralInCurve; if (_totalCollateral > _strategyDebt) { _profit = _totalCollateral - _strategyDebt; } else { _loss = _strategyDebt - _totalCollateral; } uint256 _profitAndExcessDebt = _profit + _excessDebt; if (_profitAndExcessDebt > _collateralHere) { uint256 _totalAmountToWithdraw = Math.min((_profitAndExcessDebt - _collateralHere), _collateralInCurve); if (_totalAmountToWithdraw > 0) { uint256 _lpToBurn = Math.min((_totalAmountToWithdraw * _totalLp) / _collateralInCurve, _totalLp); if (_lpToBurn > 0) { if (_lpToBurn > _lpHere) { _unstakeLp(_lpToBurn - _lpHere); } _withdrawFromCurve(_lpToBurn, _i); _collateralHere = collateralToken.balanceOf(address(this)); } } } // Make sure _collateralHere >= _payback + profit. set actual payback first and then profit _payback = Math.min(_collateralHere, _excessDebt); _profit = _collateralHere > _payback ? Math.min((_collateralHere - _payback), _profit) : 0; } function _getRewardTokens() internal view virtual returns (address[] memory _rewardTokens); function _quoteLpToCoin(uint256 amountIn_, int128 toIdx_) private view returns (uint256 _amountOut) { if (amountIn_ == 0) { return 0; } if (curvePoolType == PoolType.PLAIN_4_POOL || (curvePoolType == PoolType.META_4_POOL && !isFactoryPool)) { return IDeposit4x(depositZap).calc_withdraw_one_coin(amountIn_, toIdx_); } if (curvePoolType == PoolType.META_3_POOL || curvePoolType == PoolType.META_4_POOL) { return IDepositZap(depositZap).calc_withdraw_one_coin(address(crvLp), amountIn_, toIdx_); } return IStableSwap(crvPool).calc_withdraw_one_coin(amountIn_, toIdx_); } function _rebalance() internal virtual override returns (uint256 _profit, uint256 _loss, uint256 _payback) { (_profit, _loss, _payback) = _generateReport(); IVesperPool(pool).reportEarning(_profit, _loss, _payback); _deposit(); } // Requires that gauge has approval for lp token function _stakeAllLp() internal virtual { uint256 _balance = crvLp.balanceOf(address(this)); if (_balance > 0) { crvGauge.deposit(_balance); } } function _unstakeAllLp() internal virtual { _unstakeLp(crvGauge.balanceOf(address(this))); } function _unstakeLp(uint256 amount_) internal virtual { if (amount_ > 0) { crvGauge.withdraw(amount_); } } function _verifyCollateral(address collateralFromCurve_) internal view virtual { require(collateralFromCurve_ == address(collateralToken), "collateral-mismatch"); } function _withdrawFromPlainPool(uint256 lpAmount_, uint256 minAmountOut_, int128 i_) private { IStableSwap(crvPool).remove_liquidity_one_coin(lpAmount_, i_, minAmountOut_); } function _withdrawFrom2LendingPool(uint256 lpAmount_, uint256 minAmountOut_, int128 i_) private { // Note: Using use_underlying = true to withdraw underlying instead of IB token IStableSwap2xUnderlying(crvPool).remove_liquidity_one_coin(lpAmount_, i_, minAmountOut_, true); } function _withdrawFrom3LendingPool(uint256 lpAmount_, uint256 minAmountOut_, int128 i_) private { // Note: Using use_underlying = true to withdraw underlying instead of IB token IStableSwap3xUnderlying(crvPool).remove_liquidity_one_coin(lpAmount_, i_, minAmountOut_, true); } function _withdrawFrom4PlainOrMetaPool(uint256 lpAmount_, uint256 minAmountOut_, int128 i_) private { IDeposit4x(depositZap).remove_liquidity_one_coin(lpAmount_, i_, minAmountOut_); } function _withdrawFrom3FactoryMetaOr4FactoryMetaPool(uint256 lpAmount_, uint256 minAmountOut_, int128 i_) private { // Note: The function below won't return a reason when reverting due to slippage IDepositZap(depositZap).remove_liquidity_one_coin(address(crvLp), lpAmount_, i_, minAmountOut_); } function _withdrawFromCurve(uint256 lpToBurn_, int128 coinIdx_) internal { if (lpToBurn_ == 0) { return; } uint256 _minCoinAmountOut = _calculateAmountOutMin(address(crvLp), address(collateralToken), lpToBurn_); if (curvePoolType == PoolType.PLAIN_2_POOL || curvePoolType == PoolType.PLAIN_3_POOL) { _withdrawFromPlainPool(lpToBurn_, _minCoinAmountOut, coinIdx_); } else if (curvePoolType == PoolType.LENDING_2_POOL) { _withdrawFrom2LendingPool(lpToBurn_, _minCoinAmountOut, coinIdx_); } else if (curvePoolType == PoolType.LENDING_3_POOL) { _withdrawFrom3LendingPool(lpToBurn_, _minCoinAmountOut, coinIdx_); } else if (curvePoolType == PoolType.PLAIN_4_POOL) { _withdrawFrom4PlainOrMetaPool(lpToBurn_, _minCoinAmountOut, coinIdx_); } else if (curvePoolType == PoolType.META_3_POOL) { _withdrawFrom3FactoryMetaOr4FactoryMetaPool(lpToBurn_, _minCoinAmountOut, coinIdx_); } else if (curvePoolType == PoolType.META_4_POOL) { if (isFactoryPool) { _withdrawFrom3FactoryMetaOr4FactoryMetaPool(lpToBurn_, _minCoinAmountOut, coinIdx_); } else { _withdrawFrom4PlainOrMetaPool(lpToBurn_, _minCoinAmountOut, coinIdx_); } } else { revert("withdraw-from-curve-failed"); } } function _withdrawHere(uint256 coinAmountOut_) internal override { int128 _i = SafeCast.toInt128(int256(collateralIdx)); uint256 _lpHere = lpBalanceHere(); uint256 _totalLp = _lpHere + lpBalanceStaked(); uint256 _lpToBurn = Math.min((coinAmountOut_ * _totalLp) / _quoteLpToCoin(_totalLp, _i), _totalLp); if (_lpToBurn == 0) return; if (_lpToBurn > _lpHere) { _unstakeLp(_lpToBurn - _lpHere); } _withdrawFromCurve(_lpToBurn, _i); } /************************************************************************************************ * Governor/admin/keeper function * ***********************************************************************************************/ /** * @notice Rewards token in gauge can be updated any time. This method refresh list. * It is recommended to claimAndSwapRewards before calling this function. */ function refetchRewardTokens() external virtual onlyGovernor { // Before updating the reward list, claim rewards and swap into collateral. _claimAndSwapRewards(); rewardTokens = _getRewardTokens(); _approveToken(0); _approveToken(MAX_UINT_VALUE); } function updateCrvSlippage(uint256 newCrvSlippage_) external onlyGovernor { require(newCrvSlippage_ < MAX_BPS, "invalid-slippage-value"); emit CrvSlippageUpdated(crvSlippage, newCrvSlippage_); crvSlippage = newCrvSlippage_; } function updateMasterOracle(IMasterOracle newMasterOracle_) external onlyGovernor { emit MasterOracleUpdated(masterOracle, newMasterOracle_); masterOracle = newMasterOracle_; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; import "vesper-pools/contracts/interfaces/vesper/IVesperPool.sol"; import "vesper-pools/contracts/dependencies/openzeppelin/contracts/token/ERC20/IERC20.sol"; import "vesper-pools/contracts/dependencies/openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "vesper-pools/contracts/dependencies/openzeppelin/contracts/utils/Context.sol"; import "vesper-pools/contracts/dependencies/openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "vesper-pools/contracts/dependencies/openzeppelin/contracts/utils/math/Math.sol"; import "vesper-commons/contracts/interfaces/vesper/IStrategy.sol"; import "../interfaces/swapper/IRoutedSwapper.sol"; abstract contract Strategy is IStrategy, Context { using SafeERC20 for IERC20; using EnumerableSet for EnumerableSet.AddressSet; IERC20 public immutable collateralToken; address public receiptToken; address public immutable override pool; address public override feeCollector; IRoutedSwapper public swapper; address internal constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; uint256 internal constant MAX_UINT_VALUE = type(uint256).max; EnumerableSet.AddressSet private _keepers; event UpdatedFeeCollector(address indexed previousFeeCollector, address indexed newFeeCollector); event UpdatedSwapper(IRoutedSwapper indexed oldSwapper, IRoutedSwapper indexed newSwapper); constructor(address _pool, address _swapper, address _receiptToken) { require(_pool != address(0), "pool-address-is-zero"); require(_swapper != address(0), "swapper-address-is-zero"); swapper = IRoutedSwapper(_swapper); pool = _pool; collateralToken = IVesperPool(_pool).token(); receiptToken = _receiptToken; require(_keepers.add(_msgSender()), "add-keeper-failed"); } modifier onlyGovernor() { require(_msgSender() == IVesperPool(pool).governor(), "caller-is-not-the-governor"); _; } modifier onlyKeeper() { require(_keepers.contains(_msgSender()), "caller-is-not-a-keeper"); _; } modifier onlyPool() { require(_msgSender() == pool, "caller-is-not-vesper-pool"); _; } /** * @notice Add given address in keepers list. * @param _keeperAddress keeper address to add. */ function addKeeper(address _keeperAddress) external onlyGovernor { require(_keepers.add(_keeperAddress), "add-keeper-failed"); } /// @dev Approve all required tokens function approveToken(uint256 _approvalAmount) external onlyKeeper { _approveToken(_approvalAmount); } /// @notice Claim rewardToken and convert rewardToken into collateral token. function claimAndSwapRewards(uint256 _minAmountOut) external onlyKeeper returns (uint256 _amountOut) { uint256 _collateralBefore = collateralToken.balanceOf(address(this)); _claimAndSwapRewards(); _amountOut = collateralToken.balanceOf(address(this)) - _collateralBefore; require(_amountOut >= _minAmountOut, "not-enough-amountOut"); } /// @notice Check whether given token is reserved or not. Reserved tokens are not allowed to sweep. function isReservedToken(address _token) public view virtual override returns (bool); /// @notice Return list of keepers function keepers() external view override returns (address[] memory) { return _keepers.values(); } /** * @notice Migrate all asset and vault ownership,if any, to new strategy * @dev _beforeMigration hook can be implemented in child strategy to do extra steps. * @param _newStrategy Address of new strategy */ function migrate(address _newStrategy) external virtual override onlyPool { require(_newStrategy != address(0), "new-strategy-address-is-zero"); require(IStrategy(_newStrategy).pool() == pool, "not-valid-new-strategy"); _beforeMigration(_newStrategy); IERC20(receiptToken).safeTransfer(_newStrategy, IERC20(receiptToken).balanceOf(address(this))); collateralToken.safeTransfer(_newStrategy, collateralToken.balanceOf(address(this))); } /** * @notice OnlyKeeper: Rebalance profit, loss and investment of this strategy. * Calculate profit, loss and payback of this strategy and realize profit/loss and * withdraw fund for payback, if any, and submit this report to pool. * @return _profit Realized profit in collateral. * @return _loss Realized loss, if any, in collateral. * @return _payback If strategy has any excess debt, we have to liquidate asset to payback excess debt. */ function rebalance() external onlyKeeper returns (uint256 _profit, uint256 _loss, uint256 _payback) { return _rebalance(); } /** * @notice Remove given address from keepers list. * @param _keeperAddress keeper address to remove. */ function removeKeeper(address _keeperAddress) external onlyGovernor { require(_keepers.remove(_keeperAddress), "remove-keeper-failed"); } /// @notice onlyKeeper:: Swap given token into collateral token. function swapToCollateral(IERC20 _tokenIn, uint256 _minAmountOut) external onlyKeeper returns (uint256 _amountOut) { require(address(_tokenIn) != address(collateralToken), "not-allowed-to-sweep-collateral"); require(!isReservedToken(address(_tokenIn)), "not-allowed-to-sweep"); uint256 _collateralBefore = collateralToken.balanceOf(address(this)); uint256 _amountIn = _tokenIn.balanceOf(address(this)); if (_amountIn > 0) { if (_amountIn > _tokenIn.allowance(address(this), address(swapper))) { _tokenIn.safeApprove(address(swapper), 0); _tokenIn.safeApprove(address(swapper), MAX_UINT_VALUE); } _swapExactInput(address(_tokenIn), address(collateralToken), _amountIn); } _amountOut = collateralToken.balanceOf(address(this)) - _collateralBefore; require(_amountOut >= _minAmountOut, "not-enough-amountOut"); } /** * @notice sweep given token to feeCollector of strategy * @param _fromToken token address to sweep */ function sweep(address _fromToken) external override onlyKeeper { require(feeCollector != address(0), "fee-collector-not-set"); require(_fromToken != address(collateralToken), "not-allowed-to-sweep-collateral"); require(!isReservedToken(_fromToken), "not-allowed-to-sweep"); if (_fromToken == ETH) { Address.sendValue(payable(feeCollector), address(this).balance); } else { uint256 _amount = IERC20(_fromToken).balanceOf(address(this)); IERC20(_fromToken).safeTransfer(feeCollector, _amount); } } /// @notice Returns address of token correspond to receipt token function token() external view override returns (address) { return receiptToken; } /// @notice Returns address of token correspond to collateral token function collateral() external view override returns (address) { return address(collateralToken); } /// @notice Returns total collateral locked in the strategy function tvl() external view virtual returns (uint256); /** * @notice Update fee collector * @param _feeCollector fee collector address */ function updateFeeCollector(address _feeCollector) external onlyGovernor { require(_feeCollector != address(0), "fee-collector-address-is-zero"); require(_feeCollector != feeCollector, "fee-collector-is-same"); emit UpdatedFeeCollector(feeCollector, _feeCollector); feeCollector = _feeCollector; } /** * @notice Update swapper * @param _swapper swapper address */ function updateSwapper(IRoutedSwapper _swapper) external onlyGovernor { require(address(_swapper) != address(0), "swapper-address-is-zero"); require(_swapper != swapper, "swapper-is-same"); emit UpdatedSwapper(swapper, _swapper); swapper = _swapper; } /** * @notice Withdraw collateral token from end protocol. * @param _amount Amount of collateral token */ function withdraw(uint256 _amount) external override onlyPool { uint256 _collateralHere = collateralToken.balanceOf(address(this)); if (_collateralHere >= _amount) { collateralToken.safeTransfer(pool, _amount); } else { _withdrawHere(_amount - _collateralHere); // Do not assume _withdrawHere() will withdraw exact amount. Check balance again and transfer to pool _collateralHere = collateralToken.balanceOf(address(this)); collateralToken.safeTransfer(pool, Math.min(_amount, _collateralHere)); } } function _approveToken(uint256 _amount) internal virtual { collateralToken.safeApprove(pool, _amount); } /** * @dev some strategy may want to prepare before doing migration. * Example In Maker old strategy want to give vault ownership to new strategy * @param _newStrategy . */ function _beforeMigration(address _newStrategy) internal virtual; function _claimAndSwapRewards() internal virtual { (address _rewardToken, uint256 _rewardsAmount) = _claimRewards(); if (_rewardsAmount > 0) { _safeSwapExactInput(_rewardToken, address(collateralToken), _rewardsAmount); } } // solhint-disable-next-line no-empty-blocks function _claimRewards() internal virtual returns (address, uint256) {} function _rebalance() internal virtual returns (uint256 _profit, uint256 _loss, uint256 _payback); function _swapExactInput( address _tokenIn, address _tokenOut, uint256 _amountIn ) internal returns (uint256 _amountOut) { _amountOut = swapper.swapExactInput(_tokenIn, _tokenOut, _amountIn, 1, address(this)); } function _safeSwapExactInput(address _tokenIn, address _tokenOut, uint256 _amountIn) internal { try swapper.swapExactInput(_tokenIn, _tokenOut, _amountIn, 1, address(this)) {} catch {} //solhint-disable no-empty-blocks } // These methods must be implemented by the inheriting strategy function _withdrawHere(uint256 _amount) internal virtual; }
{ "optimizer": { "enabled": true, "runs": 500 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"pool_","type":"address"},{"internalType":"address","name":"crvPool_","type":"address"},{"internalType":"enum CurveBase.PoolType","name":"curvePoolType_","type":"uint8"},{"internalType":"address","name":"depositZap_","type":"address"},{"internalType":"address","name":"crvToken_","type":"address"},{"internalType":"uint256","name":"crvSlippage_","type":"uint256"},{"internalType":"address","name":"masterOracle_","type":"address"},{"internalType":"address","name":"swapper_","type":"address"},{"internalType":"uint256","name":"collateralIdx_","type":"uint256"},{"internalType":"uint256","name":"convexPoolId_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCrvSlippage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCrvSlippage","type":"uint256"}],"name":"CrvSlippageUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IMasterOracle","name":"oldMasterOracle","type":"address"},{"indexed":false,"internalType":"contract IMasterOracle","name":"newMasterOracle","type":"address"}],"name":"MasterOracleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldUnlockTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newUnlockTime","type":"uint256"}],"name":"UnlockTimeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousFeeCollector","type":"address"},{"indexed":true,"internalType":"address","name":"newFeeCollector","type":"address"}],"name":"UpdatedFeeCollector","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IRoutedSwapper","name":"oldSwapper","type":"address"},{"indexed":true,"internalType":"contract IRoutedSwapper","name":"newSwapper","type":"address"}],"name":"UpdatedSwapper","type":"event"},{"inputs":[],"name":"ADDRESS_PROVIDER","outputs":[{"internalType":"contract IAddressProvider","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CRV","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CRV_MINTER","outputs":[{"internalType":"contract ITokenMinter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CVX","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FXS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GAUGE_FACTORY","outputs":[{"internalType":"contract ILiquidityGaugeFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POOL_REGISTRY","outputs":[{"internalType":"contract IConvexFraxPoolRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VAULT_REGISTRY","outputs":[{"internalType":"contract IVaultRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_keeperAddress","type":"address"}],"name":"addKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_approvalAmount","type":"uint256"}],"name":"approveToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minAmountOut","type":"uint256"}],"name":"claimAndSwapRewards","outputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collateral","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralIdx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"crvGauge","outputs":[{"internalType":"contract ILiquidityGaugeV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"crvLp","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"crvPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"crvSlippage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"curvePoolType","outputs":[{"internalType":"enum CurveBase.PoolType","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fraxStaking","outputs":[{"internalType":"contract IFraxFarmERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token_","type":"address"}],"name":"isReservedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keepers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kekId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpBalanceHere","outputs":[{"internalType":"uint256","name":"_lpHere","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpBalanceHereAndStaked","outputs":[{"internalType":"uint256","name":"_lpHereAndStaked","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpBalanceStaked","outputs":[{"internalType":"uint256","name":"_total","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"masterOracle","outputs":[{"internalType":"contract IMasterOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newStrategy","type":"address"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalance","outputs":[{"internalType":"uint256","name":"_profit","type":"uint256"},{"internalType":"uint256","name":"_loss","type":"uint256"},{"internalType":"uint256","name":"_payback","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"receiptToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refetchRewardTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keeperAddress","type":"address"}],"name":"removeKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewards","outputs":[{"internalType":"contract IMultiReward","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_tokenIn","type":"address"},{"internalType":"uint256","name":"_minAmountOut","type":"uint256"}],"name":"swapToCollateral","outputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapper","outputs":[{"internalType":"contract IRoutedSwapper","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_fromToken","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tvl","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unlockTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCrvSlippage_","type":"uint256"}],"name":"updateCrvSlippage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeCollector","type":"address"}],"name":"updateFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLockPeriod_","type":"uint256"}],"name":"updateLockPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IMasterOracle","name":"newMasterOracle_","type":"address"}],"name":"updateMasterOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IRoutedSwapper","name":"_swapper","type":"address"}],"name":"updateSwapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract IStakingProxyConvex","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6102206040523480156200001257600080fd5b506040516200776a3803806200776a8339810160408190526200003591620015ea565b8a8a8a8a8a8a8a8a8a89898360006001600160a01b0383166200009f5760405162461bcd60e51b815260206004820152601460248201527f706f6f6c2d616464726573732d69732d7a65726f00000000000000000000000060448201526064015b60405180910390fd5b6001600160a01b038216620000f75760405162461bcd60e51b815260206004820152601760248201527f737761707065722d616464726573732d69732d7a65726f000000000000000000604482015260640162000096565b600280546001600160a01b0319166001600160a01b0384811691909117909155831660a081905260408051637e062a3560e11b8152905163fc0c546a91600480820192602092909190829003018186803b1580156200015557600080fd5b505afa1580156200016a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001909190620016d4565b6001600160a01b03908116608052600080546001600160a01b031916918316919091179055620001d7620001c13390565b600362000ed460201b620026f01790919060201c565b620002195760405162461bcd60e51b81526020600482015260116024820152701859190b5ad9595c195c8b59985a5b1959607a1b604482015260640162000096565b5050506001600160a01b038616620002685760405162461bcd60e51b815260206004820152601160248201527018dc9d8b5d1bdad95b8b5a5ccb5b9d5b1b607a1b604482015260640162000096565b6000806f22d53366457f9d5e68ec105046fc43836001600160a01b031663a262904b6040518163ffffffff1660e01b815260040160206040518083038186803b158015620002b557600080fd5b505afa158015620002ca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f09190620016d4565b604051633795104960e01b81526001600160a01b038d8116600483015291925060009183169063379510499060240160206040518083038186803b1580156200033857600080fd5b505afa1580156200034d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003739190620016d4565b90506001600160a01b03811615620005745760405163940494f160e01b81526001600160a01b038d8116600483015283169063940494f190602401604080518083038186803b158015620003c657600080fd5b505afa158015620003db573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004019190620016fb565b6020015185106200044a5760405162461bcd60e51b81526020600482015260126024820152711a5b9d985b1a590b58dbdb1b185d195c985b60721b604482015260640162000096565b60405163a77576ef60e01b81526001600160a01b038d81166004830152620004ed919084169063a77576ef906024016101006040518083038186803b1580156200049357600080fd5b505afa158015620004a8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004ce919062001798565b8660088110620004e257620004e262001782565b602002015162000ef4565b6040516356059ffb60e01b81526001600160a01b038d811660048301528316906356059ffb906024016101406040518083038186803b1580156200053057600080fd5b505afa15801562000545573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200056b919062001829565b519250620009c1565b60405163124fd3dd60e21b8152600360048201526000906f22d53366457f9d5e68ec105046fc43839063493f4f749060240160206040518083038186803b158015620005bf57600080fd5b505afa158015620005d4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005fa9190620016d4565b60405163e4d332a960e01b81526001600160a01b038f811660048301529192509082169063e4d332a99060240160206040518083038186803b1580156200064057600080fd5b505afa15801562000655573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200067b9190620018af565b15620007e45760405163eb73f37d60e01b81526001600160a01b038e8116600483015282169063eb73f37d90602401604080518083038186803b158015620006c257600080fd5b505afa158015620006d7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620006fd9190620016fb565b602001518610620007465760405162461bcd60e51b81526020600482015260126024820152711a5b9d985b1a590b58dbdb1b185d195c985b60721b604482015260640162000096565b60405163a77576ef60e01b81526001600160a01b038e81166004830152620007de919083169063a77576ef906024016101006040518083038186803b1580156200078f57600080fd5b505afa158015620007a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007ca919062001798565b8760088110620004e257620004e262001782565b6200093d565b60405163940494f160e01b81526001600160a01b038e8116600483015282169063940494f19060240160206040518083038186803b1580156200082657600080fd5b505afa1580156200083b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620008619190620018d3565b8610620008a65760405162461bcd60e51b81526020600482015260126024820152711a5b9d985b1a590b58dbdb1b185d195c985b60721b604482015260640162000096565b604051639ac90d3d60e01b81526001600160a01b038e811660048301526200093d9190831690639ac90d3d9060240160806040518083038186803b158015620008ee57600080fd5b505afa15801562000903573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620009299190620018ed565b8760048110620004e257620004e262001782565b60405163daf297b960e01b81526001600160a01b03808f1660048301528e935082169063daf297b99060240160206040518083038186803b1580156200098257600080fd5b505afa15801562000997573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620009bd9190620016d4565b9350505b6001600160a01b038c1662000a085760405162461bcd60e51b815260206004820152600c60248201526b1c1bdbdb0b5a5ccb5b9d5b1b60a21b604482015260640162000096565b6001600160a01b03811662000a4d5760405162461bcd60e51b815260206004820152600a6024820152691b1c0b5a5ccb5b9d5b1b60b21b604482015260640162000096565b6001600160a01b03831662000aee57604051632ecae32f60e11b81526001600160a01b038216600482015273abc000d88f23bb45525e447528dbf656a9d55bf590635d95c65e9060240160206040518083038186803b15801562000ab057600080fd5b505afa15801562000ac5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000aeb9190620016d4565b92505b6001600160a01b03831662000b365760405162461bcd60e51b815260206004820152600d60248201526c19d85d59d94b5a5ccb5b9d5b1b609a1b604482015260640162000096565b6001600160a01b03808a1660c0528c81166101005281811660e0819052908416610120526006899055600080546001600160a01b03191690911790556101408590528a600781111562000b8d5762000b8d62001972565b61018081600781111562000ba55762000ba562001972565b9052506001600160a01b038c8116828216146101a0528a811661016052600780546001600160a01b031916918916919091179055835162000bee906005906020870190620013d6565b5050604051631526fe2760e01b8152600481018f905260009c508c9b507341a5881c17185383e19df6fa4ec158a6f4851a699a50631526fe279950602401975062000c3c9650505050505050565b60a06040518083038186803b15801562000c5557600080fd5b505afa15801562000c6a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c90919062001988565b506001600160a01b03811661020052604051639abbdf4b60e01b815260048101899052929550935073569f5b842b5006ec17be02b8b94510ba8e79fbca9250639abbdf4b916024019050602060405180830381600087803b15801562000cf557600080fd5b505af115801562000d0a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000d309190620016d4565b6001600160a01b03166101e0816001600160a01b03168152505060e0516001600160a01b03166101e0516001600160a01b031663646780df6040518163ffffffff1660e01b815260040160206040518083038186803b15801562000d9357600080fd5b505afa15801562000da8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000dce9190620016d4565b6001600160a01b03161462000e1b5760405162461bcd60e51b815260206004820152601260248201527134b731b7b93932b1ba16b63816ba37b5b2b760711b604482015260640162000096565b6001600160a01b0382166101c081905260408051636e27cef960e01b81529051636e27cef991600480820192602092909190829003018186803b15801562000e6257600080fd5b505afa15801562000e77573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000e9d9190620018d3565b60095562000eaa62000f5c565b805162000ec09160089160209091019062001465565b505050505050505050505050505062001a99565b600062000eeb836001600160a01b03841662001384565b90505b92915050565b6080516001600160a01b0316816001600160a01b03161462000f595760405162461bcd60e51b815260206004820152601360248201527f636f6c6c61746572616c2d6d69736d6174636800000000000000000000000000604482015260640162000096565b50565b6060600080610200516001600160a01b031663857cb94a6040518163ffffffff1660e01b815260040160206040518083038186803b15801562000f9e57600080fd5b505afa15801562000fb3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000fd99190620018d3565b905060005b81811015620011035761020051604051637bb7bed160e01b8152600481018390526000916001600160a01b031690637bb7bed19060240160206040518083038186803b1580156200102e57600080fd5b505afa15801562001043573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620010699190620016d4565b905060c0516001600160a01b0316816001600160a01b031614158015620010ad57506001600160a01b038116734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b14155b8015620010d757506001600160a01b038116733432b6a60d23ca0dfca7761b7ab56459d9c964d014155b15620010ed5783620010e98162001a23565b9450505b5080620010fa8162001a23565b91505062000fde565b506200111182600362001a41565b6001600160401b038111156200112b576200112b6200150c565b60405190808252806020026020018201604052801562001155578160200160208202803683370190505b50925060c0518360008151811062001171576200117162001782565b60200260200101906001600160a01b031690816001600160a01b031681525050734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b83600181518110620011bc57620011bc62001782565b60200260200101906001600160a01b031690816001600160a01b031681525050733432b6a60d23ca0dfca7761b7ab56459d9c964d08360028151811062001207576200120762001782565b6001600160a01b0390921660209283029190910190910152600360005b828110156200137d5761020051604051637bb7bed160e01b8152600481018390526000916001600160a01b031690637bb7bed19060240160206040518083038186803b1580156200127457600080fd5b505afa15801562001289573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620012af9190620016d4565b905060c0516001600160a01b0316816001600160a01b031614158015620012f357506001600160a01b038116734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b14155b80156200131d57506001600160a01b038116733432b6a60d23ca0dfca7761b7ab56459d9c964d014155b156200136757808684620013318162001a23565b95508151811062001346576200134662001782565b60200260200101906001600160a01b031690816001600160a01b0316815250505b5080620013748162001a23565b91505062001224565b5050505090565b6000818152600183016020526040812054620013cd5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000eee565b50600062000eee565b828054620013e49062001a5c565b90600052602060002090601f01602090048101928262001408576000855562001453565b82601f106200142357805160ff191683800117855562001453565b8280016001018555821562001453579182015b828111156200145357825182559160200191906001019062001436565b5062001461929150620014bd565b5090565b82805482825590600052602060002090810192821562001453579160200282015b828111156200145357825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019062001486565b5b80821115620014615760008155600101620014be565b6001600160a01b038116811462000f5957600080fd5b8051620014f781620014d4565b919050565b805160088110620014f757600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156200154d576200154d6200150c565b604052919050565b600082601f8301126200156757600080fd5b81516001600160401b038111156200158357620015836200150c565b602062001599601f8301601f1916820162001522565b8281528582848701011115620015ae57600080fd5b60005b83811015620015ce578581018301518282018401528201620015b1565b83811115620015e05760008385840101525b5095945050505050565b60008060008060008060008060008060006101608c8e0312156200160d57600080fd5b8b516200161a81620014d4565b60208d0151909b506200162d81620014d4565b99506200163d60408d01620014fc565b98506200164d60608d01620014ea565b97506200165d60808d01620014ea565b965060a08c015195506200167460c08d01620014ea565b94506200168460e08d01620014ea565b6101008d01516101208e01516101408f015192965090945092506001600160401b03811115620016b357600080fd5b620016c18e828f0162001555565b9150509295989b509295989b9093969950565b600060208284031215620016e757600080fd5b8151620016f481620014d4565b9392505050565b6000604082840312156200170e57600080fd5b82601f8301126200171e57600080fd5b604080519081016001600160401b03811182821017156200174357620017436200150c565b80604052508060408401858111156200175b57600080fd5b845b81811015620017775780518352602092830192016200175d565b509195945050505050565b634e487b7160e01b600052603260045260246000fd5b6000610100808385031215620017ad57600080fd5b83601f840112620017bd57600080fd5b6040518181016001600160401b0381118282101715620017e157620017e16200150c565b604052908301908085831115620017f757600080fd5b845b838110156200181e5780516200180f81620014d4565b825260209182019101620017f9565b509095945050505050565b60006101408083850312156200183e57600080fd5b83601f8401126200184e57600080fd5b6040518181016001600160401b03811182821017156200187257620018726200150c565b6040529083019080858311156200188857600080fd5b845b838110156200181e578051620018a081620014d4565b8252602091820191016200188a565b600060208284031215620018c257600080fd5b81518015158114620016f457600080fd5b600060208284031215620018e657600080fd5b5051919050565b6000608082840312156200190057600080fd5b82601f8301126200191057600080fd5b604051608081016001600160401b03811182821017156200193557620019356200150c565b6040528060808401858111156200194b57600080fd5b845b81811015620017775780516200196381620014d4565b8352602092830192016200194d565b634e487b7160e01b600052602160045260246000fd5b600080600080600060a08688031215620019a157600080fd5b8551620019ae81620014d4565b6020870151909550620019c181620014d4565b6040870151909450620019d481620014d4565b6060870151909350620019e781620014d4565b608087015190925060ff81168114620019ff57600080fd5b809150509295509295909350565b634e487b7160e01b600052601160045260246000fd5b600060001982141562001a3a5762001a3a62001a0d565b5060010190565b6000821982111562001a575762001a5762001a0d565b500190565b600181811c9082168062001a7157607f821691505b6020821081141562001a9357634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e051610200516158ec62001e7e6000396000818161065b01528181612b1501528181612bca0152612e4e0152600081816107f301528181611a6a01528181612ae9015281816138ca0152818161394e01528181614553015281816149860152614a000152600081816107cc015281816117000152611a9501526000818161336e01528181613d880152614e000152600081816103c1015281816132f901528181613334015281816134420152818161347d01528181613bbb01528181613bf601528181613c3c01528181613c8101528181613cc601528181613d0b01528181613d5001528181614c2a01528181614c6f01528181614cb401528181614cf901528181614d3e01528181614d830152614dc80152600081816133b40152818161350401528181613f4c01528181613fa801528181613ffc0152818161479f0152818161482d015281816151b30152818161524f015261530d0152600081816105270152818161225b015281816129f10152818161416701528181614ec701528181614f9b0152818161503a015281816150d6015281816151750152818161521101526152cf01526000818161082b0152613f250152600081816106d10152818161355301528181613e4a015281816146a90152818161474101528181614f0501528181614fd901528181615078015281816151140152818161528401526153420152600081816105e50152818161135f01528181611507015281816121bc01528181612ac70152818161315d015281816134cb01528181613b6f01528181613f0301528181613fda015281816147ed015281816148d30152614bff01526000818161061f01528181612c5001528181612d4e0152612ed401526000818161042901528181610aca01528181610e2101528181610f580152818161109f0152818161117401528181611227015281816113d601528181611621015281816118ab01528181611ac901528181611b9601528181611dc101528181611fb001528181612ff101528181614047015281816140e4015261488b0152600081816106aa0152818161075a0152818161092201528181610ca101528181610d4401528181610fe50152818161107d015281816110eb015281816111a70152818161139a01528181611d45015281816122990152818161232201528181612407015281816125d5015281816126130152818161299d0152818161306c01528181613b9001528181613e2801528181613e7c01528181613f86015281816141de0152818161431d015281816143fc015281816148690152614bde01526158ec6000f3fe608060405234801561001057600080fd5b50600436106103575760003560e01c80637f44579b116101c8578063d2c35ce811610104578063ec78e832116100a2578063fbfa77cf1161007c578063fbfa77cf146107ee578063fc0c546a14610815578063fd57a4df14610826578063ffa1ad741461084d57600080fd5b8063ec78e832146107a1578063ee330ee3146107b4578063eff40c45146107c757600080fd5b8063d8dfeb45116100de578063d8dfeb4514610758578063de603fdc1461077e578063e5328e0614610786578063eaada3821461078e57600080fd5b8063d2c35ce814610729578063d3033c391461073c578063d572fd7f1461074f57600080fd5b8063abc9b45e11610171578063c415b95c1161014b578063c415b95c146106f3578063c4f59f9b14610706578063c965fa8a1461070e578063ce5494bb1461071657600080fd5b8063abc9b45e14610692578063b2016bd4146106a5578063b20fdc0d146106cc57600080fd5b8063951dc22c116101a2578063951dc22c146106415780639ec5a89414610656578063a3f4df7e1461067d57600080fd5b80637f44579b146105e057806391db7b0d14610607578063945c91421461061a57600080fd5b80633ac9fc11116102975780634a2b9e07116102405780637752e1941161021a5780637752e1941461059a578063795dae66146105a25780637bb7bed1146105aa5780637d7c2a1c146105bd57600080fd5b80634a2b9e071461054957806374db9ad414610564578063759cb53b1461057f57600080fd5b8063440d724811610271578063440d7248146104f657806345bffdf61461051957806348cd2ddd1461052257600080fd5b80633ac9fc11146104c75780633fd8b02f146104da5780634032b72b146104e357600080fd5b806316f0115b11610304578063200ea222116102de578063200ea2221461047d578063251c1aa3146104985780632b3297f9146104a15780632e1a7d4d146104b457600080fd5b806316f0115b146104245780631848effa1461044b5780631cda4a8d1461046257600080fd5b806306beb80a1161033557806306beb80a146103bc5780631026013a146103f057806314ae9f2e1461041157600080fd5b806301681a621461035c57806302ace7fe1461037157806304f4efc5146103a9575b600080fd5b61036f61036a366004615466565b610871565b005b61038c73569f5b842b5006ec17be02b8b94510ba8e79fbca81565b6040516001600160a01b0390911681526020015b60405180910390f35b61036f6103b7366004615483565b610ac8565b6103e37f000000000000000000000000000000000000000000000000000000000000000081565b6040516103a091906154b2565b6104036103fe366004615483565b610c39565b6040519081526020016103a0565b61036f61041f366004615466565b610e1f565b61038c7f000000000000000000000000000000000000000000000000000000000000000081565b61038c6f22d53366457f9d5e68ec105046fc438381565b61038c7341a5881c17185383e19df6fa4ec158a6f4851a6981565b61038c733432b6a60d23ca0dfca7761b7ab56459d9c964d081565b610403600b5481565b60025461038c906001600160a01b031681565b61036f6104c2366004615483565b610f55565b61036f6104d5366004615483565b6111ce565b61040360095481565b61036f6104f1366004615466565b611225565b610509610504366004615466565b61135b565b60405190151581526020016103a0565b610403600a5481565b6104037f000000000000000000000000000000000000000000000000000000000000000081565b61038c73abc000d88f23bb45525e447528dbf656a9d55bf581565b61038c73d061d61a4d941c39e5453435b6345dc261c2fce081565b61038c734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b81565b61036f6113d4565b6104036114ef565b61038c6105b8366004615483565b61158f565b6105c56115b9565b604080519384526020840192909252908201526060016103a0565b61038c7f000000000000000000000000000000000000000000000000000000000000000081565b61036f610615366004615483565b61161f565b61038c7f000000000000000000000000000000000000000000000000000000000000000081565b61064961180f565b6040516103a091906154da565b61038c7f000000000000000000000000000000000000000000000000000000000000000081565b61068561181b565b6040516103a09190615553565b61036f6106a0366004615466565b6118a9565b61038c7f000000000000000000000000000000000000000000000000000000000000000081565b61038c7f000000000000000000000000000000000000000000000000000000000000000081565b60015461038c906001600160a01b031681565b6106496119f1565b610403611a53565b61036f610724366004615466565b611ac6565b61036f610737366004615466565b611dbf565b61036f61074a366004615466565b611fae565b61040360065481565b7f000000000000000000000000000000000000000000000000000000000000000061038c565b61040361219d565b610403612249565b60075461038c906001600160a01b031681565b60005461038c906001600160a01b031681565b6104036107c2366004615586565b6122d0565b61038c7f000000000000000000000000000000000000000000000000000000000000000081565b61038c7f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b031661038c565b61038c7f000000000000000000000000000000000000000000000000000000000000000081565b610685604051806040016040528060058152602001640352e312e360dc1b81525081565b61087e335b60039061270c565b6108c85760405162461bcd60e51b815260206004820152601660248201527531b0b63632b916b4b996b737ba16b096b5b2b2b832b960511b60448201526064015b60405180910390fd5b6001546001600160a01b03166109205760405162461bcd60e51b815260206004820152601560248201527f6665652d636f6c6c6563746f722d6e6f742d736574000000000000000000000060448201526064016108bf565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031614156109a25760405162461bcd60e51b815260206004820152601f60248201527f6e6f742d616c6c6f7765642d746f2d73776565702d636f6c6c61746572616c0060448201526064016108bf565b6109ab8161135b565b156109ef5760405162461bcd60e51b815260206004820152601460248201527306e6f742d616c6c6f7765642d746f2d73776565760641b60448201526064016108bf565b6001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415610a2d57600154610a2a906001600160a01b03164761272e565b50565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b158015610a6f57600080fd5b505afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa791906155b2565b600154909150610ac4906001600160a01b0384811691168361284c565b5050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610b2157600080fd5b505afa158015610b35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5991906155cb565b6001600160a01b0316336001600160a01b031614610ba75760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b6127108110610bf85760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642d736c6970706167652d76616c75650000000000000000000060448201526064016108bf565b60065460408051918252602082018390527f43a94473b3422f31e660358900c02b907f22142a3224beace1f2b9f1fa079a9e910160405180910390a1600655565b6000610c4433610876565b610c895760405162461bcd60e51b815260206004820152601660248201527531b0b63632b916b4b996b737ba16b096b5b2b2b832b960511b60448201526064016108bf565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015610ceb57600080fd5b505afa158015610cff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2391906155b2565b9050610d2d6128dc565b6040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015610d8e57600080fd5b505afa158015610da2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc691906155b2565b610dd091906155fe565b915082821015610e195760405162461bcd60e51b81526020600482015260146024820152731b9bdd0b595b9bdd59da0b585b5bdd5b9d13dd5d60621b60448201526064016108bf565b50919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610e7857600080fd5b505afa158015610e8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb091906155cb565b6001600160a01b0316336001600160a01b031614610efe5760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b610f096003826129d5565b610a2a5760405162461bcd60e51b815260206004820152601460248201527f72656d6f76652d6b65657065722d6661696c656400000000000000000000000060448201526064016108bf565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614610fcd5760405162461bcd60e51b815260206004820152601960248201527f63616c6c65722d69732d6e6f742d7665737065722d706f6f6c0000000000000060448201526064016108bf565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561102f57600080fd5b505afa158015611043573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106791906155b2565b90508181106110c457610ac46001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000008461284c565b6110d66110d182846155fe565b6129ea565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561113557600080fd5b505afa158015611149573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116d91906155b2565b9050610ac47f000000000000000000000000000000000000000000000000000000000000000061119d8484612a9b565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061284c565b6111d733610876565b61121c5760405162461bcd60e51b815260206004820152601660248201527531b0b63632b916b4b996b737ba16b096b5b2b2b832b960511b60448201526064016108bf565b610a2a81612ab1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561127e57600080fd5b505afa158015611292573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b691906155cb565b6001600160a01b0316336001600160a01b0316146113045760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b61130f6003826126f0565b610a2a5760405162461bcd60e51b815260206004820152601160248201527f6164642d6b65657065722d6661696c656400000000000000000000000000000060448201526064016108bf565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614806113ce57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316145b92915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561142d57600080fd5b505afa158015611441573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061146591906155cb565b6001600160a01b0316336001600160a01b0316146114b35760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b6114bb6128dc565b6114c3612b0e565b80516114d791600891602090910190615381565b506114e26000612ab1565b6114ed600019612ab1565b565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a08231906024015b60206040518083038186803b15801561155257600080fd5b505afa158015611566573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158a91906155b2565b905090565b6008818154811061159f57600080fd5b6000918252602090912001546001600160a01b0316905081565b600080806115c633610876565b61160b5760405162461bcd60e51b815260206004820152601660248201527531b0b63632b916b4b996b737ba16b096b5b2b2b832b960511b60448201526064016108bf565b611613612fb8565b9250925092505b909192565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561167857600080fd5b505afa15801561168c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b091906155cb565b6001600160a01b0316336001600160a01b0316146116fe5760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636e27cef96040518163ffffffff1660e01b815260040160206040518083038186803b15801561175757600080fd5b505afa15801561176b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061178f91906155b2565b8110156117ce5760405162461bcd60e51b815260206004820152600d60248201526c3832b934b7b216b63a16b6b4b760991b60448201526064016108bf565b60095460408051918252602082018390527ffe56e44f0698c36962f6cf507a9af4bcb609a7681784d38395451b065bd2ac6d910160405180910390a1600955565b606061158a600361305d565b6005805461182890615615565b80601f016020809104026020016040519081016040528092919081815260200182805461185490615615565b80156118a15780601f10611876576101008083540402835291602001916118a1565b820191906000526020600020905b81548152906001019060200180831161188457829003601f168201915b505050505081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561190257600080fd5b505afa158015611916573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193a91906155cb565b6001600160a01b0316336001600160a01b0316146119885760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b600754604080516001600160a01b03928316815291831660208301527fc96bca3f57d35a1057a3357bced51fac157918147faa56845639671c516ec69c910160405180910390a1600780546001600160a01b0319166001600160a01b0392909216919091179055565b60606008805480602002602001604051908101604052809291908181526020018280548015611a4957602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611a2b575b5050505050905090565b60405163d9f96e8d60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063d9f96e8d9060240161153a565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614611b3e5760405162461bcd60e51b815260206004820152601960248201527f63616c6c65722d69732d6e6f742d7665737065722d706f6f6c0000000000000060448201526064016108bf565b6001600160a01b038116611b945760405162461bcd60e51b815260206004820152601c60248201527f6e65772d73747261746567792d616464726573732d69732d7a65726f0000000060448201526064016108bf565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611bf757600080fd5b505afa158015611c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2f91906155cb565b6001600160a01b031614611c855760405162461bcd60e51b815260206004820152601660248201527f6e6f742d76616c69642d6e65772d73747261746567790000000000000000000060448201526064016108bf565b611c8e8161306a565b6000546040516370a0823160e01b8152306004820152611d229183916001600160a01b03909116906370a082319060240160206040518083038186803b158015611cd757600080fd5b505afa158015611ceb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0f91906155b2565b6000546001600160a01b0316919061284c565b6040516370a0823160e01b8152306004820152610a2a9082906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b158015611d8757600080fd5b505afa158015611d9b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119d91906155b2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015611e1857600080fd5b505afa158015611e2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5091906155cb565b6001600160a01b0316336001600160a01b031614611e9e5760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b6001600160a01b038116611ef45760405162461bcd60e51b815260206004820152601d60248201527f6665652d636f6c6c6563746f722d616464726573732d69732d7a65726f00000060448201526064016108bf565b6001546001600160a01b0382811691161415611f525760405162461bcd60e51b815260206004820152601560248201527f6665652d636f6c6c6563746f722d69732d73616d65000000000000000000000060448201526064016108bf565b6001546040516001600160a01b038084169216907f0f06062680f9bd68e786e9980d9bb03d73d5620fc3b345e417b6eacb310b970690600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561200757600080fd5b505afa15801561201b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203f91906155cb565b6001600160a01b0316336001600160a01b03161461208d5760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b6001600160a01b0381166120e35760405162461bcd60e51b815260206004820152601760248201527f737761707065722d616464726573732d69732d7a65726f00000000000000000060448201526064016108bf565b6002546001600160a01b03828116911614156121415760405162461bcd60e51b815260206004820152600f60248201527f737761707065722d69732d73616d65000000000000000000000000000000000060448201526064016108bf565b6002546040516001600160a01b038084169216907f6c953b7ec311055c20b96a42cea31e89528e375b1bf953a503db40854b3188fe90600090a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b60006121a7611a53565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a08231906024015b60206040518083038186803b15801561220757600080fd5b505afa15801561221b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061223f91906155b2565b61158a919061564a565b600061228461225661219d565b61227f7f0000000000000000000000000000000000000000000000000000000000000000613254565b6132e6565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a08231906024016121ef565b60006122db33610876565b6123205760405162461bcd60e51b815260206004820152601660248201527531b0b63632b916b4b996b737ba16b096b5b2b2b832b960511b60448201526064016108bf565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031614156123a25760405162461bcd60e51b815260206004820152601f60248201527f6e6f742d616c6c6f7765642d746f2d73776565702d636f6c6c61746572616c0060448201526064016108bf565b6123ab8361135b565b156123ef5760405162461bcd60e51b815260206004820152601460248201527306e6f742d616c6c6f7765642d746f2d73776565760641b60448201526064016108bf565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561245157600080fd5b505afa158015612465573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061248991906155b2565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038616906370a082319060240160206040518083038186803b1580156124ce57600080fd5b505afa1580156124e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061250691906155b2565b905080156125fc57600254604051636eb1769f60e11b81523060048201526001600160a01b0391821660248201529086169063dd62ed3e9060440160206040518083038186803b15801561255957600080fd5b505afa15801561256d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061259191906155b2565b8111156125cf576002546125b3906001600160a01b03878116911660006135d5565b6002546125cf906001600160a01b0387811691166000196135d5565b6125fa857f000000000000000000000000000000000000000000000000000000000000000083613700565b505b6040516370a0823160e01b815230600482015282907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561265d57600080fd5b505afa158015612671573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061269591906155b2565b61269f91906155fe565b9250838310156126e85760405162461bcd60e51b81526020600482015260146024820152731b9bdd0b595b9bdd59da0b585b5bdd5b9d13dd5d60621b60448201526064016108bf565b505092915050565b6000612705836001600160a01b0384166137a4565b9392505050565b6001600160a01b03811660009081526001830160205260408120541515612705565b8047101561277e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016108bf565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146127cb576040519150601f19603f3d011682016040523d82523d6000602084013e6127d0565b606091505b50509050806128475760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016108bf565b505050565b6040516001600160a01b03831660248201526044810182905261284790849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526137f3565b6128e46138c5565b505060085460005b81811015610ac45760006008828154811061290957612909615662565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561295757600080fd5b505afa15801561296b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061298f91906155b2565b905080156129c2576129c2827f0000000000000000000000000000000000000000000000000000000000000000836139bc565b5050806129ce90615678565b90506128ec565b6000612705836001600160a01b038416613a5e565b6000612a157f0000000000000000000000000000000000000000000000000000000000000000613254565b90506000612a216114ef565b90506000612a2d611a53565b612a37908361564a565b90506000612a62612a4883866132e6565b612a528488615693565b612a5c91906156b2565b83612a9b565b905080612a70575050505050565b82811115612a8a57612a8a612a8584836155fe565b613b51565b612a948185613b5f565b5050505050565b6000818310612aaa5781612705565b5090919050565b612aba81613e0a565b610a2a6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000836135d5565b60606000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663857cb94a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612b6c57600080fd5b505afa158015612b80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ba491906155b2565b905060005b81811015612cfc57604051637bb7bed160e01b8152600481018290526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690637bb7bed19060240160206040518083038186803b158015612c1457600080fd5b505afa158015612c28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c4c91906155cb565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031614158015612cad57506001600160a01b038116734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b14155b8015612cd657506001600160a01b038116733432b6a60d23ca0dfca7761b7ab56459d9c964d014155b15612ce95783612ce581615678565b9450505b5080612cf481615678565b915050612ba9565b50612d0882600361564a565b67ffffffffffffffff811115612d2057612d206156d4565b604051908082528060200260200182016040528015612d49578160200160208202803683370190505b5092507f000000000000000000000000000000000000000000000000000000000000000083600081518110612d8057612d80615662565b60200260200101906001600160a01b031690816001600160a01b031681525050734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b83600181518110612dc857612dc8615662565b60200260200101906001600160a01b031690816001600160a01b031681525050733432b6a60d23ca0dfca7761b7ab56459d9c964d083600281518110612e1057612e10615662565b6001600160a01b0390921660209283029190910190910152600360005b82811015612fb157604051637bb7bed160e01b8152600481018290526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690637bb7bed19060240160206040518083038186803b158015612e9857600080fd5b505afa158015612eac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ed091906155cb565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031614158015612f3157506001600160a01b038116734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b14155b8015612f5a57506001600160a01b038116733432b6a60d23ca0dfca7761b7ab56459d9c964d014155b15612f9e57808684612f6b81615678565b955081518110612f7d57612f7d615662565b60200260200101906001600160a01b031690816001600160a01b0316815250505b5080612fa981615678565b915050612e2d565b5050505090565b6000806000612fc5614021565b6040516302df682360e11b815260048101849052602481018390526044810182905292955090935091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906305bed04690606401600060405180830381600087803b15801561303d57600080fd5b505af1158015613051573d6000803e3d6000fd5b5050505061161a6143e3565b606060006127058361448b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031663d8dfeb456040518163ffffffff1660e01b815260040160206040518083038186803b1580156130cd57600080fd5b505afa1580156130e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061310591906155cb565b6001600160a01b03161461315b5760405162461bcd60e51b815260206004820152601660248201527f77726f6e672d636f6c6c61746572616c2d746f6b656e0000000000000000000060448201526064016108bf565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156131be57600080fd5b505afa1580156131d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f691906155cb565b6001600160a01b03161461324c5760405162461bcd60e51b815260206004820152601360248201527f77726f6e672d726563656970742d746f6b656e0000000000000000000000000060448201526064016108bf565b610a2a6144e7565b60006f7fffffffffffffffffffffffffffffff19821215801561328657506f8000000000000000000000000000000082125b6132e25760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b60648201526084016108bf565b5090565b6000826132f5575060006113ce565b60027f000000000000000000000000000000000000000000000000000000000000000060078111156133295761332961549c565b148061338f575060077f000000000000000000000000000000000000000000000000000000000000000060078111156133645761336461549c565b14801561338f57507f0000000000000000000000000000000000000000000000000000000000000000155b1561343e5760405163cc2b27d760e01b815260048101849052600f83900b60248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063cc2b27d7906044015b60206040518083038186803b1580156133ff57600080fd5b505afa158015613413573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061343791906155b2565b90506113ce565b60067f000000000000000000000000000000000000000000000000000000000000000060078111156134725761347261549c565b14806134af575060077f000000000000000000000000000000000000000000000000000000000000000060078111156134ad576134ad61549c565b145b15613533576040516341b028f360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260248201859052600f84900b60448301527f000000000000000000000000000000000000000000000000000000000000000016906341b028f3906064016133e7565b60405163cc2b27d760e01b815260048101849052600f83900b60248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063cc2b27d79060440160206040518083038186803b15801561359d57600080fd5b505afa1580156135b1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061270591906155b2565b80158061365e5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b15801561362457600080fd5b505afa158015613638573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061365c91906155b2565b155b6136d05760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084016108bf565b6040516001600160a01b03831660248201526044810182905261284790849063095ea7b360e01b90606401612878565b600254604051636ccb2b0160e01b81526001600160a01b038581166004830152848116602483015260448201849052600160648301523060848301526000921690636ccb2b019060a401602060405180830381600087803b15801561376457600080fd5b505af1158015613778573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061379c91906155b2565b949350505050565b60008181526001830160205260408120546137eb575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556113ce565b5060006113ce565b6000613848826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166145be9092919063ffffffff16565b805190915015612847578080602001905181019061386691906156ea565b6128475760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016108bf565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633d18b9126040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561392357600080fd5b505af1925050508015613934575060015b6139b35760405163a4698feb60e01b8152600060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4698feb90602401600060405180830381600087803b15801561399a57600080fd5b505af11580156139ae573d6000803e3d6000fd5b505050505b50600091829150565b600254604051636ccb2b0160e01b81526001600160a01b0385811660048301528481166024830152604482018490526001606483015230608483015290911690636ccb2b019060a401602060405180830381600087803b158015613a1f57600080fd5b505af1925050508015613a4f575060408051601f3d908101601f19168201909252613a4c918101906155b2565b60015b613a5857505050565b50505050565b60008181526001830160205260408120548015613b47576000613a826001836155fe565b8554909150600090613a96906001906155fe565b9050818114613afb576000866000018281548110613ab657613ab6615662565b9060005260206000200154905080876000018481548110613ad957613ad9615662565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613b0c57613b0c61570c565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506113ce565b60009150506113ce565b8015610a2a57610a2a6144e7565b81613b68575050565b6000613bb57f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000856145cd565b905060007f00000000000000000000000000000000000000000000000000000000000000006007811115613beb57613beb61549c565b1480613c28575060017f00000000000000000000000000000000000000000000000000000000000000006007811115613c2657613c2661549c565b145b15613c3857612847838284614682565b60037f00000000000000000000000000000000000000000000000000000000000000006007811115613c6c57613c6c61549c565b1415613c7d57612847838284614713565b60047f00000000000000000000000000000000000000000000000000000000000000006007811115613cb157613cb161549c565b1415613cc257612847838284614713565b60027f00000000000000000000000000000000000000000000000000000000000000006007811115613cf657613cf661549c565b1415613d0757612847838284614778565b60067f00000000000000000000000000000000000000000000000000000000000000006007811115613d3b57613d3b61549c565b1415613d4c576128478382846147d6565b60077f00000000000000000000000000000000000000000000000000000000000000006007811115613d8057613d8061549c565b1415613dc2577f000000000000000000000000000000000000000000000000000000000000000015613db7576128478382846147d6565b612847838284614778565b60405162461bcd60e51b815260206004820152601a60248201527f77697468647261772d66726f6d2d63757276652d6661696c656400000000000060448201526064016108bf565b613e138161485c565b6002546001600160a01b0390811690613e6f907f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000846135d5565b613ea36001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682846135d5565b60085460005b81811015613ef557613ee5838560088481548110613ec957613ec9615662565b6000918252602090912001546001600160a01b031691906135d5565b613eee81615678565b9050613ea9565b50613f4a6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000856135d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161561284757613fcd6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000856135d5565b6128476001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000856135d5565b604051636a9eee1360e11b81523060048201526000908190819081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d53ddc269060240160206040518083038186803b15801561408957600080fd5b505afa15801561409d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140c191906155b2565b604051639f2b283360e01b81523060048201529091506000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639f2b28339060240160206040518083038186803b15801561412657600080fd5b505afa15801561413a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061415e91906155b2565b9050600061418b7f0000000000000000000000000000000000000000000000000000000000000000613254565b905060006141976114ef565b905060006141a3611a53565b6141ad908361564a565b905060006141bb82856132e6565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b15801561422057600080fd5b505afa158015614234573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061425891906155b2565b90506000614266838361564a565b9050868111156142815761427a87826155fe565b9a5061428e565b61428b81886155fe565b99505b600061429a898d61564a565b9050828111156143a65760006142b96142b385846155fe565b86612a9b565b905080156143a45760006142e1866142d18985615693565b6142db91906156b2565b88612a9b565b905080156143a257878111156142fe576142fe612a8589836155fe565b614308818a613b5f565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561436757600080fd5b505afa15801561437b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061439f91906155b2565b94505b505b505b6143b0838a612a9b565b99508983116143c05760006143d3565b6143d36143cd8b856155fe565b8d612a9b565b9b50505050505050505050909192565b6040516370a0823160e01b8152306004820152614483907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561444657600080fd5b505afa15801561445a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061447e91906155b2565b6148b0565b6114ed6148bb565b6060816000018054806020026020016040519081016040528092919081815260200182805480156144db57602002820191906000526020600020905b8154815260200190600101908083116144c7575b50505050509050919050565b600b544210156145395760405162461bcd60e51b815260206004820152601660248201527f756e6c6f636b2d74696d652d6469646e742d706173730000000000000000000060448201526064016108bf565b600a54604051634ab794a360e01b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690634ab794a390602401600060405180830381600087803b15801561459f57600080fd5b505af11580156145b3573d6000803e3d6000fd5b50506000600a555050565b606061379c8484600085614aa6565b60006127106006546127106145e291906155fe565b600754604051632d9198e160e21b81526001600160a01b0388811660048301528781166024830152604482018790529091169063b64663849060640160206040518083038186803b15801561463657600080fd5b505afa15801561464a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061466e91906155b2565b6146789190615693565b61379c91906156b2565b604051630d2680e960e11b815260048101849052600f82900b6024820152604481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631a4d01d2906064015b600060405180830381600087803b1580156146f657600080fd5b505af115801561470a573d6000803e3d6000fd5b50505050505050565b60405163517a55a360e01b815260048101849052600f82900b602482015260448101839052600160648201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063517a55a3906084016146dc565b604051630d2680e960e11b815260048101849052600f82900b6024820152604481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631a4d01d2906064016146dc565b6040516314f6943160e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260248201859052600f83900b6044830152606482018490527f000000000000000000000000000000000000000000000000000000000000000016906329ed2862906084016146dc565b610a2a6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000836135d5565b610a2a816000614bce565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561491d57600080fd5b505afa158015614931573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061495591906155b2565b90508015610a2a57600a54156149e657600a54604051630687c4bd60e01b81526004810191909152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630687c4bd90604401600060405180830381600087803b1580156149d257600080fd5b505af1158015612a94573d6000803e3d6000fd5b60095460405163a41ce7e960e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a41ce7e991614a3e918591600401918252602082015260400190565b602060405180830381600087803b158015614a5857600080fd5b505af1158015614a6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a9091906155b2565b600a55600954614aa0904261564a565b600b5550565b606082471015614b075760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016108bf565b843b614b555760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108bf565b600080866001600160a01b03168587604051614b719190615722565b60006040518083038185875af1925050503d8060008114614bae576040519150601f19603f3d011682016040523d82523d6000602084013e614bb3565b606091505b5091509150614bc3828286614e82565b979650505050505050565b81614bd7575050565b6000614c247f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000856145cd565b905060007f00000000000000000000000000000000000000000000000000000000000000006007811115614c5a57614c5a61549c565b1415614c6b57612847838284614ebb565b60037f00000000000000000000000000000000000000000000000000000000000000006007811115614c9f57614c9f61549c565b1415614cb057612847838284614f8f565b60017f00000000000000000000000000000000000000000000000000000000000000006007811115614ce457614ce461549c565b1415614cf55761284783828461502e565b60047f00000000000000000000000000000000000000000000000000000000000000006007811115614d2957614d2961549c565b1415614d3a576128478382846150ca565b60027f00000000000000000000000000000000000000000000000000000000000000006007811115614d6e57614d6e61549c565b1415614d7f57612847838284615169565b60067f00000000000000000000000000000000000000000000000000000000000000006007811115614db357614db361549c565b1415614dc457612847838284615205565b60077f00000000000000000000000000000000000000000000000000000000000000006007811115614df857614df861549c565b1415614e3a577f000000000000000000000000000000000000000000000000000000000000000015614e2f576128478382846152c3565b612847838284615169565b60405162461bcd60e51b815260206004820152601760248201527f6465706f7369742d746f2d63757276652d6661696c656400000000000000000060448201526064016108bf565b60608315614e91575081612705565b825115614ea15782518084602001fd5b8160405162461bcd60e51b81526004016108bf9190615553565b614ec36153e2565b83817f000000000000000000000000000000000000000000000000000000000000000060028110614ef657614ef6615662565b60200201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016630b4c7e4d83614f36576000614f38565b855b83866040518463ffffffff1660e01b8152600401614f57929190615761565b6000604051808303818588803b158015614f7057600080fd5b505af1158015614f84573d6000803e3d6000fd5b505050505050505050565b614f976153e2565b83817f000000000000000000000000000000000000000000000000000000000000000060028110614fca57614fca615662565b60200201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663ee22be238361500a57600061500c565b855b838660016040518563ffffffff1660e01b8152600401614f579392919061577c565b615036615400565b83817f00000000000000000000000000000000000000000000000000000000000000006003811061506957615069615662565b60200201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016634515cef3836150a95760006150ab565b855b83866040518463ffffffff1660e01b8152600401614f579291906157c3565b6150d2615400565b83817f00000000000000000000000000000000000000000000000000000000000000006003811061510557615105615662565b60200201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016632b6e993a83615145576000615147565b855b838660016040518563ffffffff1660e01b8152600401614f57939291906157de565b61517161541e565b83817f0000000000000000000000000000000000000000000000000000000000000000600481106151a4576151a4615662565b60200201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663029b2f34836151e45760006151e6565b855b83866040518463ffffffff1660e01b8152600401614f57929190615825565b61520d615400565b83817f00000000000000000000000000000000000000000000000000000000000000006003811061524057615240615662565b60200201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663a318517983615280576000615282565b855b7f000000000000000000000000000000000000000000000000000000000000000084876040518563ffffffff1660e01b8152600401614f5793929190615840565b6152cb61541e565b83817f0000000000000000000000000000000000000000000000000000000000000000600481106152fe576152fe615662565b60200201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663384e03db8361533e576000615340565b855b7f000000000000000000000000000000000000000000000000000000000000000084876040518563ffffffff1660e01b8152600401614f579392919061586b565b8280548282559060005260206000209081019282156153d6579160200282015b828111156153d657825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906153a1565b506132e292915061543c565b60405180604001604052806002906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b5b808211156132e2576000815560010161543d565b6001600160a01b0381168114610a2a57600080fd5b60006020828403121561547857600080fd5b813561270581615451565b60006020828403121561549557600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b60208101600883106154d457634e487b7160e01b600052602160045260246000fd5b91905290565b6020808252825182820181905260009190848201906040850190845b8181101561551b5783516001600160a01b0316835292840192918401916001016154f6565b50909695505050505050565b60005b8381101561554257818101518382015260200161552a565b83811115613a585750506000910152565b6020815260008251806020840152615572816040850160208701615527565b601f01601f19169190910160400192915050565b6000806040838503121561559957600080fd5b82356155a481615451565b946020939093013593505050565b6000602082840312156155c457600080fd5b5051919050565b6000602082840312156155dd57600080fd5b815161270581615451565b634e487b7160e01b600052601160045260246000fd5b600082821015615610576156106155e8565b500390565b600181811c9082168061562957607f821691505b60208210811415610e1957634e487b7160e01b600052602260045260246000fd5b6000821982111561565d5761565d6155e8565b500190565b634e487b7160e01b600052603260045260246000fd5b600060001982141561568c5761568c6155e8565b5060010190565b60008160001904831182151516156156ad576156ad6155e8565b500290565b6000826156cf57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156156fc57600080fd5b8151801515811461270557600080fd5b634e487b7160e01b600052603160045260246000fd5b60008251615734818460208701615527565b9190910192915050565b8060005b6002811015613a58578151845260209384019390910190600101615742565b6060810161576f828561573e565b8260408301529392505050565b6080810161578a828661573e565b8360408301528215156060830152949350505050565b8060005b6003811015613a585781518452602093840193909101906001016157a4565b608081016157d182856157a0565b8260608301529392505050565b60a081016157ec82866157a0565b8360608301528215156080830152949350505050565b8060005b6004811015613a58578151845260209384019390910190600101615806565b60a081016158338285615802565b8260808301529392505050565b6001600160a01b038416815260a0810161585d60208301856157a0565b826080830152949350505050565b6001600160a01b038416815260c081016158886020830185615802565b8260a083015294935050505056fe63616c6c65722d69732d6e6f742d7468652d676f7665726e6f72000000000000a26469706673582212206563c0403c9c81451e1ae05fe03ff2fe4984fd0a26ef8326c5cc9de89de6ee2a64736f6c63430008090033000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a80452000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f000000000000000000000000000000000000000000000000000000000000000600000000000000000000000008780fb7e580e492c1935bee4fa5920b94aa95da000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd52000000000000000000000000000000000000000000000000000000000000006400000000000000000000000080704acdf97723963263c78f861f091ad04f46e2000000000000000000000000229f19942612a8dbdec3643cb23f88685ccd56a50000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000001d436f6e766578466f72467261785f657573646672617862705f55534443000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103575760003560e01c80637f44579b116101c8578063d2c35ce811610104578063ec78e832116100a2578063fbfa77cf1161007c578063fbfa77cf146107ee578063fc0c546a14610815578063fd57a4df14610826578063ffa1ad741461084d57600080fd5b8063ec78e832146107a1578063ee330ee3146107b4578063eff40c45146107c757600080fd5b8063d8dfeb45116100de578063d8dfeb4514610758578063de603fdc1461077e578063e5328e0614610786578063eaada3821461078e57600080fd5b8063d2c35ce814610729578063d3033c391461073c578063d572fd7f1461074f57600080fd5b8063abc9b45e11610171578063c415b95c1161014b578063c415b95c146106f3578063c4f59f9b14610706578063c965fa8a1461070e578063ce5494bb1461071657600080fd5b8063abc9b45e14610692578063b2016bd4146106a5578063b20fdc0d146106cc57600080fd5b8063951dc22c116101a2578063951dc22c146106415780639ec5a89414610656578063a3f4df7e1461067d57600080fd5b80637f44579b146105e057806391db7b0d14610607578063945c91421461061a57600080fd5b80633ac9fc11116102975780634a2b9e07116102405780637752e1941161021a5780637752e1941461059a578063795dae66146105a25780637bb7bed1146105aa5780637d7c2a1c146105bd57600080fd5b80634a2b9e071461054957806374db9ad414610564578063759cb53b1461057f57600080fd5b8063440d724811610271578063440d7248146104f657806345bffdf61461051957806348cd2ddd1461052257600080fd5b80633ac9fc11146104c75780633fd8b02f146104da5780634032b72b146104e357600080fd5b806316f0115b11610304578063200ea222116102de578063200ea2221461047d578063251c1aa3146104985780632b3297f9146104a15780632e1a7d4d146104b457600080fd5b806316f0115b146104245780631848effa1461044b5780631cda4a8d1461046257600080fd5b806306beb80a1161033557806306beb80a146103bc5780631026013a146103f057806314ae9f2e1461041157600080fd5b806301681a621461035c57806302ace7fe1461037157806304f4efc5146103a9575b600080fd5b61036f61036a366004615466565b610871565b005b61038c73569f5b842b5006ec17be02b8b94510ba8e79fbca81565b6040516001600160a01b0390911681526020015b60405180910390f35b61036f6103b7366004615483565b610ac8565b6103e37f000000000000000000000000000000000000000000000000000000000000000681565b6040516103a091906154b2565b6104036103fe366004615483565b610c39565b6040519081526020016103a0565b61036f61041f366004615466565b610e1f565b61038c7f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a8045281565b61038c6f22d53366457f9d5e68ec105046fc438381565b61038c7341a5881c17185383e19df6fa4ec158a6f4851a6981565b61038c733432b6a60d23ca0dfca7761b7ab56459d9c964d081565b610403600b5481565b60025461038c906001600160a01b031681565b61036f6104c2366004615483565b610f55565b61036f6104d5366004615483565b6111ce565b61040360095481565b61036f6104f1366004615466565b611225565b610509610504366004615466565b61135b565b60405190151581526020016103a0565b610403600a5481565b6104037f000000000000000000000000000000000000000000000000000000000000000281565b61038c73abc000d88f23bb45525e447528dbf656a9d55bf581565b61038c73d061d61a4d941c39e5453435b6345dc261c2fce081565b61038c734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b81565b61036f6113d4565b6104036114ef565b61038c6105b8366004615483565b61158f565b6105c56115b9565b604080519384526020840192909252908201526060016103a0565b61038c7f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f81565b61036f610615366004615483565b61161f565b61038c7f000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd5281565b61064961180f565b6040516103a091906154da565b61038c7f00000000000000000000000032791df95565661450eee7778f0cc6c2ad04466b81565b61068561181b565b6040516103a09190615553565b61036f6106a0366004615466565b6118a9565b61038c7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b61038c7f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f81565b60015461038c906001600160a01b031681565b6106496119f1565b610403611a53565b61036f610724366004615466565b611ac6565b61036f610737366004615466565b611dbf565b61036f61074a366004615466565b611fae565b61040360065481565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4861038c565b61040361219d565b610403612249565b60075461038c906001600160a01b031681565b60005461038c906001600160a01b031681565b6104036107c2366004615586565b6122d0565b61038c7f0000000000000000000000004c9ad8c53d0a001e7ff08a3e5e26de6795bea5ac81565b61038c7f0000000000000000000000004c88884389548e6acaeeabcb6f3ed31aeb42e37081565b6000546001600160a01b031661038c565b61038c7f0000000000000000000000008605dc0c339a2e7e85eea043bd29d42da2c6d78481565b610685604051806040016040528060058152602001640352e312e360dc1b81525081565b61087e335b60039061270c565b6108c85760405162461bcd60e51b815260206004820152601660248201527531b0b63632b916b4b996b737ba16b096b5b2b2b832b960511b60448201526064015b60405180910390fd5b6001546001600160a01b03166109205760405162461bcd60e51b815260206004820152601560248201527f6665652d636f6c6c6563746f722d6e6f742d736574000000000000000000000060448201526064016108bf565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316816001600160a01b031614156109a25760405162461bcd60e51b815260206004820152601f60248201527f6e6f742d616c6c6f7765642d746f2d73776565702d636f6c6c61746572616c0060448201526064016108bf565b6109ab8161135b565b156109ef5760405162461bcd60e51b815260206004820152601460248201527306e6f742d616c6c6f7765642d746f2d73776565760641b60448201526064016108bf565b6001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415610a2d57600154610a2a906001600160a01b03164761272e565b50565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b158015610a6f57600080fd5b505afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa791906155b2565b600154909150610ac4906001600160a01b0384811691168361284c565b5050565b7f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a804526001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610b2157600080fd5b505afa158015610b35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5991906155cb565b6001600160a01b0316336001600160a01b031614610ba75760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b6127108110610bf85760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642d736c6970706167652d76616c75650000000000000000000060448201526064016108bf565b60065460408051918252602082018390527f43a94473b3422f31e660358900c02b907f22142a3224beace1f2b9f1fa079a9e910160405180910390a1600655565b6000610c4433610876565b610c895760405162461bcd60e51b815260206004820152601660248201527531b0b63632b916b4b996b737ba16b096b5b2b2b832b960511b60448201526064016108bf565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a082319060240160206040518083038186803b158015610ceb57600080fd5b505afa158015610cff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2391906155b2565b9050610d2d6128dc565b6040516370a0823160e01b815230600482015281907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a082319060240160206040518083038186803b158015610d8e57600080fd5b505afa158015610da2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc691906155b2565b610dd091906155fe565b915082821015610e195760405162461bcd60e51b81526020600482015260146024820152731b9bdd0b595b9bdd59da0b585b5bdd5b9d13dd5d60621b60448201526064016108bf565b50919050565b7f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a804526001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610e7857600080fd5b505afa158015610e8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb091906155cb565b6001600160a01b0316336001600160a01b031614610efe5760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b610f096003826129d5565b610a2a5760405162461bcd60e51b815260206004820152601460248201527f72656d6f76652d6b65657065722d6661696c656400000000000000000000000060448201526064016108bf565b337f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a804526001600160a01b031614610fcd5760405162461bcd60e51b815260206004820152601960248201527f63616c6c65722d69732d6e6f742d7665737065722d706f6f6c0000000000000060448201526064016108bf565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a082319060240160206040518083038186803b15801561102f57600080fd5b505afa158015611043573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106791906155b2565b90508181106110c457610ac46001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48167f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a804528461284c565b6110d66110d182846155fe565b6129ea565b6040516370a0823160e01b81523060048201527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a082319060240160206040518083038186803b15801561113557600080fd5b505afa158015611149573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116d91906155b2565b9050610ac47f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a8045261119d8484612a9b565b6001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816919061284c565b6111d733610876565b61121c5760405162461bcd60e51b815260206004820152601660248201527531b0b63632b916b4b996b737ba16b096b5b2b2b832b960511b60448201526064016108bf565b610a2a81612ab1565b7f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a804526001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561127e57600080fd5b505afa158015611292573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b691906155cb565b6001600160a01b0316336001600160a01b0316146113045760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b61130f6003826126f0565b610a2a5760405162461bcd60e51b815260206004820152601160248201527f6164642d6b65657065722d6661696c656400000000000000000000000000000060448201526064016108bf565b60007f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f6001600160a01b0316826001600160a01b031614806113ce57507f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316826001600160a01b0316145b92915050565b7f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a804526001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561142d57600080fd5b505afa158015611441573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061146591906155cb565b6001600160a01b0316336001600160a01b0316146114b35760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b6114bb6128dc565b6114c3612b0e565b80516114d791600891602090910190615381565b506114e26000612ab1565b6114ed600019612ab1565b565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f6001600160a01b0316906370a08231906024015b60206040518083038186803b15801561155257600080fd5b505afa158015611566573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158a91906155b2565b905090565b6008818154811061159f57600080fd5b6000918252602090912001546001600160a01b0316905081565b600080806115c633610876565b61160b5760405162461bcd60e51b815260206004820152601660248201527531b0b63632b916b4b996b737ba16b096b5b2b2b832b960511b60448201526064016108bf565b611613612fb8565b9250925092505b909192565b7f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a804526001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561167857600080fd5b505afa15801561168c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b091906155cb565b6001600160a01b0316336001600160a01b0316146116fe5760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b7f0000000000000000000000004c9ad8c53d0a001e7ff08a3e5e26de6795bea5ac6001600160a01b0316636e27cef96040518163ffffffff1660e01b815260040160206040518083038186803b15801561175757600080fd5b505afa15801561176b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061178f91906155b2565b8110156117ce5760405162461bcd60e51b815260206004820152600d60248201526c3832b934b7b216b63a16b6b4b760991b60448201526064016108bf565b60095460408051918252602082018390527ffe56e44f0698c36962f6cf507a9af4bcb609a7681784d38395451b065bd2ac6d910160405180910390a1600955565b606061158a600361305d565b6005805461182890615615565b80601f016020809104026020016040519081016040528092919081815260200182805461185490615615565b80156118a15780601f10611876576101008083540402835291602001916118a1565b820191906000526020600020905b81548152906001019060200180831161188457829003601f168201915b505050505081565b7f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a804526001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561190257600080fd5b505afa158015611916573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193a91906155cb565b6001600160a01b0316336001600160a01b0316146119885760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b600754604080516001600160a01b03928316815291831660208301527fc96bca3f57d35a1057a3357bced51fac157918147faa56845639671c516ec69c910160405180910390a1600780546001600160a01b0319166001600160a01b0392909216919091179055565b60606008805480602002602001604051908101604052809291908181526020018280548015611a4957602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611a2b575b5050505050905090565b60405163d9f96e8d60e01b81526001600160a01b037f0000000000000000000000004c88884389548e6acaeeabcb6f3ed31aeb42e370811660048301526000917f0000000000000000000000004c9ad8c53d0a001e7ff08a3e5e26de6795bea5ac9091169063d9f96e8d9060240161153a565b337f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a804526001600160a01b031614611b3e5760405162461bcd60e51b815260206004820152601960248201527f63616c6c65722d69732d6e6f742d7665737065722d706f6f6c0000000000000060448201526064016108bf565b6001600160a01b038116611b945760405162461bcd60e51b815260206004820152601c60248201527f6e65772d73747261746567792d616464726573732d69732d7a65726f0000000060448201526064016108bf565b7f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a804526001600160a01b0316816001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611bf757600080fd5b505afa158015611c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2f91906155cb565b6001600160a01b031614611c855760405162461bcd60e51b815260206004820152601660248201527f6e6f742d76616c69642d6e65772d73747261746567790000000000000000000060448201526064016108bf565b611c8e8161306a565b6000546040516370a0823160e01b8152306004820152611d229183916001600160a01b03909116906370a082319060240160206040518083038186803b158015611cd757600080fd5b505afa158015611ceb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0f91906155b2565b6000546001600160a01b0316919061284c565b6040516370a0823160e01b8152306004820152610a2a9082906001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816906370a082319060240160206040518083038186803b158015611d8757600080fd5b505afa158015611d9b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119d91906155b2565b7f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a804526001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015611e1857600080fd5b505afa158015611e2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5091906155cb565b6001600160a01b0316336001600160a01b031614611e9e5760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b6001600160a01b038116611ef45760405162461bcd60e51b815260206004820152601d60248201527f6665652d636f6c6c6563746f722d616464726573732d69732d7a65726f00000060448201526064016108bf565b6001546001600160a01b0382811691161415611f525760405162461bcd60e51b815260206004820152601560248201527f6665652d636f6c6c6563746f722d69732d73616d65000000000000000000000060448201526064016108bf565b6001546040516001600160a01b038084169216907f0f06062680f9bd68e786e9980d9bb03d73d5620fc3b345e417b6eacb310b970690600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b7f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a804526001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561200757600080fd5b505afa15801561201b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203f91906155cb565b6001600160a01b0316336001600160a01b03161461208d5760405162461bcd60e51b815260206004820152601a602482015260008051602061589783398151915260448201526064016108bf565b6001600160a01b0381166120e35760405162461bcd60e51b815260206004820152601760248201527f737761707065722d616464726573732d69732d7a65726f00000000000000000060448201526064016108bf565b6002546001600160a01b03828116911614156121415760405162461bcd60e51b815260206004820152600f60248201527f737761707065722d69732d73616d65000000000000000000000000000000000060448201526064016108bf565b6002546040516001600160a01b038084169216907f6c953b7ec311055c20b96a42cea31e89528e375b1bf953a503db40854b3188fe90600090a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b60006121a7611a53565b6040516370a0823160e01b81523060048201527f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f6001600160a01b0316906370a08231906024015b60206040518083038186803b15801561220757600080fd5b505afa15801561221b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061223f91906155b2565b61158a919061564a565b600061228461225661219d565b61227f7f0000000000000000000000000000000000000000000000000000000000000002613254565b6132e6565b6040516370a0823160e01b81523060048201527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a08231906024016121ef565b60006122db33610876565b6123205760405162461bcd60e51b815260206004820152601660248201527531b0b63632b916b4b996b737ba16b096b5b2b2b832b960511b60448201526064016108bf565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316836001600160a01b031614156123a25760405162461bcd60e51b815260206004820152601f60248201527f6e6f742d616c6c6f7765642d746f2d73776565702d636f6c6c61746572616c0060448201526064016108bf565b6123ab8361135b565b156123ef5760405162461bcd60e51b815260206004820152601460248201527306e6f742d616c6c6f7765642d746f2d73776565760641b60448201526064016108bf565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a082319060240160206040518083038186803b15801561245157600080fd5b505afa158015612465573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061248991906155b2565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038616906370a082319060240160206040518083038186803b1580156124ce57600080fd5b505afa1580156124e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061250691906155b2565b905080156125fc57600254604051636eb1769f60e11b81523060048201526001600160a01b0391821660248201529086169063dd62ed3e9060440160206040518083038186803b15801561255957600080fd5b505afa15801561256d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061259191906155b2565b8111156125cf576002546125b3906001600160a01b03878116911660006135d5565b6002546125cf906001600160a01b0387811691166000196135d5565b6125fa857f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4883613700565b505b6040516370a0823160e01b815230600482015282907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a082319060240160206040518083038186803b15801561265d57600080fd5b505afa158015612671573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061269591906155b2565b61269f91906155fe565b9250838310156126e85760405162461bcd60e51b81526020600482015260146024820152731b9bdd0b595b9bdd59da0b585b5bdd5b9d13dd5d60621b60448201526064016108bf565b505092915050565b6000612705836001600160a01b0384166137a4565b9392505050565b6001600160a01b03811660009081526001830160205260408120541515612705565b8047101561277e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016108bf565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146127cb576040519150601f19603f3d011682016040523d82523d6000602084013e6127d0565b606091505b50509050806128475760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016108bf565b505050565b6040516001600160a01b03831660248201526044810182905261284790849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526137f3565b6128e46138c5565b505060085460005b81811015610ac45760006008828154811061290957612909615662565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561295757600080fd5b505afa15801561296b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061298f91906155b2565b905080156129c2576129c2827f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48836139bc565b5050806129ce90615678565b90506128ec565b6000612705836001600160a01b038416613a5e565b6000612a157f0000000000000000000000000000000000000000000000000000000000000002613254565b90506000612a216114ef565b90506000612a2d611a53565b612a37908361564a565b90506000612a62612a4883866132e6565b612a528488615693565b612a5c91906156b2565b83612a9b565b905080612a70575050505050565b82811115612a8a57612a8a612a8584836155fe565b613b51565b612a948185613b5f565b5050505050565b6000818310612aaa5781612705565b5090919050565b612aba81613e0a565b610a2a6001600160a01b037f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f167f0000000000000000000000004c88884389548e6acaeeabcb6f3ed31aeb42e370836135d5565b60606000807f00000000000000000000000032791df95565661450eee7778f0cc6c2ad04466b6001600160a01b031663857cb94a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612b6c57600080fd5b505afa158015612b80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ba491906155b2565b905060005b81811015612cfc57604051637bb7bed160e01b8152600481018290526000907f00000000000000000000000032791df95565661450eee7778f0cc6c2ad04466b6001600160a01b031690637bb7bed19060240160206040518083038186803b158015612c1457600080fd5b505afa158015612c28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c4c91906155cb565b90507f000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd526001600160a01b0316816001600160a01b031614158015612cad57506001600160a01b038116734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b14155b8015612cd657506001600160a01b038116733432b6a60d23ca0dfca7761b7ab56459d9c964d014155b15612ce95783612ce581615678565b9450505b5080612cf481615678565b915050612ba9565b50612d0882600361564a565b67ffffffffffffffff811115612d2057612d206156d4565b604051908082528060200260200182016040528015612d49578160200160208202803683370190505b5092507f000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd5283600081518110612d8057612d80615662565b60200260200101906001600160a01b031690816001600160a01b031681525050734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b83600181518110612dc857612dc8615662565b60200260200101906001600160a01b031690816001600160a01b031681525050733432b6a60d23ca0dfca7761b7ab56459d9c964d083600281518110612e1057612e10615662565b6001600160a01b0390921660209283029190910190910152600360005b82811015612fb157604051637bb7bed160e01b8152600481018290526000907f00000000000000000000000032791df95565661450eee7778f0cc6c2ad04466b6001600160a01b031690637bb7bed19060240160206040518083038186803b158015612e9857600080fd5b505afa158015612eac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ed091906155cb565b90507f000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd526001600160a01b0316816001600160a01b031614158015612f3157506001600160a01b038116734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b14155b8015612f5a57506001600160a01b038116733432b6a60d23ca0dfca7761b7ab56459d9c964d014155b15612f9e57808684612f6b81615678565b955081518110612f7d57612f7d615662565b60200260200101906001600160a01b031690816001600160a01b0316815250505b5080612fa981615678565b915050612e2d565b5050505090565b6000806000612fc5614021565b6040516302df682360e11b815260048101849052602481018390526044810182905292955090935091507f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a804526001600160a01b0316906305bed04690606401600060405180830381600087803b15801561303d57600080fd5b505af1158015613051573d6000803e3d6000fd5b5050505061161a6143e3565b606060006127058361448b565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316816001600160a01b031663d8dfeb456040518163ffffffff1660e01b815260040160206040518083038186803b1580156130cd57600080fd5b505afa1580156130e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061310591906155cb565b6001600160a01b03161461315b5760405162461bcd60e51b815260206004820152601660248201527f77726f6e672d636f6c6c61746572616c2d746f6b656e0000000000000000000060448201526064016108bf565b7f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f6001600160a01b0316816001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156131be57600080fd5b505afa1580156131d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f691906155cb565b6001600160a01b03161461324c5760405162461bcd60e51b815260206004820152601360248201527f77726f6e672d726563656970742d746f6b656e0000000000000000000000000060448201526064016108bf565b610a2a6144e7565b60006f7fffffffffffffffffffffffffffffff19821215801561328657506f8000000000000000000000000000000082125b6132e25760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b60648201526084016108bf565b5090565b6000826132f5575060006113ce565b60027f000000000000000000000000000000000000000000000000000000000000000660078111156133295761332961549c565b148061338f575060077f000000000000000000000000000000000000000000000000000000000000000660078111156133645761336461549c565b14801561338f57507f0000000000000000000000000000000000000000000000000000000000000001155b1561343e5760405163cc2b27d760e01b815260048101849052600f83900b60248201527f00000000000000000000000008780fb7e580e492c1935bee4fa5920b94aa95da6001600160a01b03169063cc2b27d7906044015b60206040518083038186803b1580156133ff57600080fd5b505afa158015613413573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061343791906155b2565b90506113ce565b60067f000000000000000000000000000000000000000000000000000000000000000660078111156134725761347261549c565b14806134af575060077f000000000000000000000000000000000000000000000000000000000000000660078111156134ad576134ad61549c565b145b15613533576040516341b028f360e01b81526001600160a01b037f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f8116600483015260248201859052600f84900b60448301527f00000000000000000000000008780fb7e580e492c1935bee4fa5920b94aa95da16906341b028f3906064016133e7565b60405163cc2b27d760e01b815260048101849052600f83900b60248201527f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f6001600160a01b03169063cc2b27d79060440160206040518083038186803b15801561359d57600080fd5b505afa1580156135b1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061270591906155b2565b80158061365e5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b15801561362457600080fd5b505afa158015613638573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061365c91906155b2565b155b6136d05760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084016108bf565b6040516001600160a01b03831660248201526044810182905261284790849063095ea7b360e01b90606401612878565b600254604051636ccb2b0160e01b81526001600160a01b038581166004830152848116602483015260448201849052600160648301523060848301526000921690636ccb2b019060a401602060405180830381600087803b15801561376457600080fd5b505af1158015613778573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061379c91906155b2565b949350505050565b60008181526001830160205260408120546137eb575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556113ce565b5060006113ce565b6000613848826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166145be9092919063ffffffff16565b805190915015612847578080602001905181019061386691906156ea565b6128475760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016108bf565b6000807f0000000000000000000000004c88884389548e6acaeeabcb6f3ed31aeb42e3706001600160a01b0316633d18b9126040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561392357600080fd5b505af1925050508015613934575060015b6139b35760405163a4698feb60e01b8152600060048201527f0000000000000000000000004c88884389548e6acaeeabcb6f3ed31aeb42e3706001600160a01b03169063a4698feb90602401600060405180830381600087803b15801561399a57600080fd5b505af11580156139ae573d6000803e3d6000fd5b505050505b50600091829150565b600254604051636ccb2b0160e01b81526001600160a01b0385811660048301528481166024830152604482018490526001606483015230608483015290911690636ccb2b019060a401602060405180830381600087803b158015613a1f57600080fd5b505af1925050508015613a4f575060408051601f3d908101601f19168201909252613a4c918101906155b2565b60015b613a5857505050565b50505050565b60008181526001830160205260408120548015613b47576000613a826001836155fe565b8554909150600090613a96906001906155fe565b9050818114613afb576000866000018281548110613ab657613ab6615662565b9060005260206000200154905080876000018481548110613ad957613ad9615662565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613b0c57613b0c61570c565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506113ce565b60009150506113ce565b8015610a2a57610a2a6144e7565b81613b68575050565b6000613bb57f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48856145cd565b905060007f00000000000000000000000000000000000000000000000000000000000000066007811115613beb57613beb61549c565b1480613c28575060017f00000000000000000000000000000000000000000000000000000000000000066007811115613c2657613c2661549c565b145b15613c3857612847838284614682565b60037f00000000000000000000000000000000000000000000000000000000000000066007811115613c6c57613c6c61549c565b1415613c7d57612847838284614713565b60047f00000000000000000000000000000000000000000000000000000000000000066007811115613cb157613cb161549c565b1415613cc257612847838284614713565b60027f00000000000000000000000000000000000000000000000000000000000000066007811115613cf657613cf661549c565b1415613d0757612847838284614778565b60067f00000000000000000000000000000000000000000000000000000000000000066007811115613d3b57613d3b61549c565b1415613d4c576128478382846147d6565b60077f00000000000000000000000000000000000000000000000000000000000000066007811115613d8057613d8061549c565b1415613dc2577f000000000000000000000000000000000000000000000000000000000000000115613db7576128478382846147d6565b612847838284614778565b60405162461bcd60e51b815260206004820152601a60248201527f77697468647261772d66726f6d2d63757276652d6661696c656400000000000060448201526064016108bf565b613e138161485c565b6002546001600160a01b0390811690613e6f907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48167f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f846135d5565b613ea36001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481682846135d5565b60085460005b81811015613ef557613ee5838560088481548110613ec957613ec9615662565b6000918252602090912001546001600160a01b031691906135d5565b613eee81615678565b9050613ea9565b50613f4a6001600160a01b037f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f167f0000000000000000000000008605dc0c339a2e7e85eea043bd29d42da2c6d784856135d5565b7f00000000000000000000000008780fb7e580e492c1935bee4fa5920b94aa95da6001600160a01b03161561284757613fcd6001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48167f00000000000000000000000008780fb7e580e492c1935bee4fa5920b94aa95da856135d5565b6128476001600160a01b037f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f167f00000000000000000000000008780fb7e580e492c1935bee4fa5920b94aa95da856135d5565b604051636a9eee1360e11b81523060048201526000908190819081906001600160a01b037f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a80452169063d53ddc269060240160206040518083038186803b15801561408957600080fd5b505afa15801561409d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140c191906155b2565b604051639f2b283360e01b81523060048201529091506000906001600160a01b037f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a804521690639f2b28339060240160206040518083038186803b15801561412657600080fd5b505afa15801561413a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061415e91906155b2565b9050600061418b7f0000000000000000000000000000000000000000000000000000000000000002613254565b905060006141976114ef565b905060006141a3611a53565b6141ad908361564a565b905060006141bb82856132e6565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816906370a082319060240160206040518083038186803b15801561422057600080fd5b505afa158015614234573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061425891906155b2565b90506000614266838361564a565b9050868111156142815761427a87826155fe565b9a5061428e565b61428b81886155fe565b99505b600061429a898d61564a565b9050828111156143a65760006142b96142b385846155fe565b86612a9b565b905080156143a45760006142e1866142d18985615693565b6142db91906156b2565b88612a9b565b905080156143a257878111156142fe576142fe612a8589836155fe565b614308818a613b5f565b6040516370a0823160e01b81523060048201527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a082319060240160206040518083038186803b15801561436757600080fd5b505afa15801561437b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061439f91906155b2565b94505b505b505b6143b0838a612a9b565b99508983116143c05760006143d3565b6143d36143cd8b856155fe565b8d612a9b565b9b50505050505050505050909192565b6040516370a0823160e01b8152306004820152614483907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a082319060240160206040518083038186803b15801561444657600080fd5b505afa15801561445a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061447e91906155b2565b6148b0565b6114ed6148bb565b6060816000018054806020026020016040519081016040528092919081815260200182805480156144db57602002820191906000526020600020905b8154815260200190600101908083116144c7575b50505050509050919050565b600b544210156145395760405162461bcd60e51b815260206004820152601660248201527f756e6c6f636b2d74696d652d6469646e742d706173730000000000000000000060448201526064016108bf565b600a54604051634ab794a360e01b815260048101919091527f0000000000000000000000004c88884389548e6acaeeabcb6f3ed31aeb42e3706001600160a01b031690634ab794a390602401600060405180830381600087803b15801561459f57600080fd5b505af11580156145b3573d6000803e3d6000fd5b50506000600a555050565b606061379c8484600085614aa6565b60006127106006546127106145e291906155fe565b600754604051632d9198e160e21b81526001600160a01b0388811660048301528781166024830152604482018790529091169063b64663849060640160206040518083038186803b15801561463657600080fd5b505afa15801561464a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061466e91906155b2565b6146789190615693565b61379c91906156b2565b604051630d2680e960e11b815260048101849052600f82900b6024820152604481018390527f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f6001600160a01b031690631a4d01d2906064015b600060405180830381600087803b1580156146f657600080fd5b505af115801561470a573d6000803e3d6000fd5b50505050505050565b60405163517a55a360e01b815260048101849052600f82900b602482015260448101839052600160648201527f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f6001600160a01b03169063517a55a3906084016146dc565b604051630d2680e960e11b815260048101849052600f82900b6024820152604481018390527f00000000000000000000000008780fb7e580e492c1935bee4fa5920b94aa95da6001600160a01b031690631a4d01d2906064016146dc565b6040516314f6943160e11b81526001600160a01b037f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f8116600483015260248201859052600f83900b6044830152606482018490527f00000000000000000000000008780fb7e580e492c1935bee4fa5920b94aa95da16906329ed2862906084016146dc565b610a2a6001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48167f000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a80452836135d5565b610a2a816000614bce565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f6001600160a01b0316906370a082319060240160206040518083038186803b15801561491d57600080fd5b505afa158015614931573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061495591906155b2565b90508015610a2a57600a54156149e657600a54604051630687c4bd60e01b81526004810191909152602481018290527f0000000000000000000000004c88884389548e6acaeeabcb6f3ed31aeb42e3706001600160a01b031690630687c4bd90604401600060405180830381600087803b1580156149d257600080fd5b505af1158015612a94573d6000803e3d6000fd5b60095460405163a41ce7e960e01b81526001600160a01b037f0000000000000000000000004c88884389548e6acaeeabcb6f3ed31aeb42e370169163a41ce7e991614a3e918591600401918252602082015260400190565b602060405180830381600087803b158015614a5857600080fd5b505af1158015614a6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a9091906155b2565b600a55600954614aa0904261564a565b600b5550565b606082471015614b075760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016108bf565b843b614b555760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108bf565b600080866001600160a01b03168587604051614b719190615722565b60006040518083038185875af1925050503d8060008114614bae576040519150601f19603f3d011682016040523d82523d6000602084013e614bb3565b606091505b5091509150614bc3828286614e82565b979650505050505050565b81614bd7575050565b6000614c247f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb487f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f856145cd565b905060007f00000000000000000000000000000000000000000000000000000000000000066007811115614c5a57614c5a61549c565b1415614c6b57612847838284614ebb565b60037f00000000000000000000000000000000000000000000000000000000000000066007811115614c9f57614c9f61549c565b1415614cb057612847838284614f8f565b60017f00000000000000000000000000000000000000000000000000000000000000066007811115614ce457614ce461549c565b1415614cf55761284783828461502e565b60047f00000000000000000000000000000000000000000000000000000000000000066007811115614d2957614d2961549c565b1415614d3a576128478382846150ca565b60027f00000000000000000000000000000000000000000000000000000000000000066007811115614d6e57614d6e61549c565b1415614d7f57612847838284615169565b60067f00000000000000000000000000000000000000000000000000000000000000066007811115614db357614db361549c565b1415614dc457612847838284615205565b60077f00000000000000000000000000000000000000000000000000000000000000066007811115614df857614df861549c565b1415614e3a577f000000000000000000000000000000000000000000000000000000000000000115614e2f576128478382846152c3565b612847838284615169565b60405162461bcd60e51b815260206004820152601760248201527f6465706f7369742d746f2d63757276652d6661696c656400000000000000000060448201526064016108bf565b60608315614e91575081612705565b825115614ea15782518084602001fd5b8160405162461bcd60e51b81526004016108bf9190615553565b614ec36153e2565b83817f000000000000000000000000000000000000000000000000000000000000000260028110614ef657614ef6615662565b60200201526001600160a01b037f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f16630b4c7e4d83614f36576000614f38565b855b83866040518463ffffffff1660e01b8152600401614f57929190615761565b6000604051808303818588803b158015614f7057600080fd5b505af1158015614f84573d6000803e3d6000fd5b505050505050505050565b614f976153e2565b83817f000000000000000000000000000000000000000000000000000000000000000260028110614fca57614fca615662565b60200201526001600160a01b037f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f1663ee22be238361500a57600061500c565b855b838660016040518563ffffffff1660e01b8152600401614f579392919061577c565b615036615400565b83817f00000000000000000000000000000000000000000000000000000000000000026003811061506957615069615662565b60200201526001600160a01b037f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f16634515cef3836150a95760006150ab565b855b83866040518463ffffffff1660e01b8152600401614f579291906157c3565b6150d2615400565b83817f00000000000000000000000000000000000000000000000000000000000000026003811061510557615105615662565b60200201526001600160a01b037f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f16632b6e993a83615145576000615147565b855b838660016040518563ffffffff1660e01b8152600401614f57939291906157de565b61517161541e565b83817f0000000000000000000000000000000000000000000000000000000000000002600481106151a4576151a4615662565b60200201526001600160a01b037f00000000000000000000000008780fb7e580e492c1935bee4fa5920b94aa95da1663029b2f34836151e45760006151e6565b855b83866040518463ffffffff1660e01b8152600401614f57929190615825565b61520d615400565b83817f00000000000000000000000000000000000000000000000000000000000000026003811061524057615240615662565b60200201526001600160a01b037f00000000000000000000000008780fb7e580e492c1935bee4fa5920b94aa95da1663a318517983615280576000615282565b855b7f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f84876040518563ffffffff1660e01b8152600401614f5793929190615840565b6152cb61541e565b83817f0000000000000000000000000000000000000000000000000000000000000002600481106152fe576152fe615662565b60200201526001600160a01b037f00000000000000000000000008780fb7e580e492c1935bee4fa5920b94aa95da1663384e03db8361533e576000615340565b855b7f000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f84876040518563ffffffff1660e01b8152600401614f579392919061586b565b8280548282559060005260206000209081019282156153d6579160200282015b828111156153d657825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906153a1565b506132e292915061543c565b60405180604001604052806002906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b5b808211156132e2576000815560010161543d565b6001600160a01b0381168114610a2a57600080fd5b60006020828403121561547857600080fd5b813561270581615451565b60006020828403121561549557600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b60208101600883106154d457634e487b7160e01b600052602160045260246000fd5b91905290565b6020808252825182820181905260009190848201906040850190845b8181101561551b5783516001600160a01b0316835292840192918401916001016154f6565b50909695505050505050565b60005b8381101561554257818101518382015260200161552a565b83811115613a585750506000910152565b6020815260008251806020840152615572816040850160208701615527565b601f01601f19169190910160400192915050565b6000806040838503121561559957600080fd5b82356155a481615451565b946020939093013593505050565b6000602082840312156155c457600080fd5b5051919050565b6000602082840312156155dd57600080fd5b815161270581615451565b634e487b7160e01b600052601160045260246000fd5b600082821015615610576156106155e8565b500390565b600181811c9082168061562957607f821691505b60208210811415610e1957634e487b7160e01b600052602260045260246000fd5b6000821982111561565d5761565d6155e8565b500190565b634e487b7160e01b600052603260045260246000fd5b600060001982141561568c5761568c6155e8565b5060010190565b60008160001904831182151516156156ad576156ad6155e8565b500290565b6000826156cf57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156156fc57600080fd5b8151801515811461270557600080fd5b634e487b7160e01b600052603160045260246000fd5b60008251615734818460208701615527565b9190910192915050565b8060005b6002811015613a58578151845260209384019390910190600101615742565b6060810161576f828561573e565b8260408301529392505050565b6080810161578a828661573e565b8360408301528215156060830152949350505050565b8060005b6003811015613a585781518452602093840193909101906001016157a4565b608081016157d182856157a0565b8260608301529392505050565b60a081016157ec82866157a0565b8360608301528215156080830152949350505050565b8060005b6004811015613a58578151845260209384019390910190600101615806565b60a081016158338285615802565b8260808301529392505050565b6001600160a01b038416815260a0810161585d60208301856157a0565b826080830152949350505050565b6001600160a01b038416815260c081016158886020830185615802565b8260a083015294935050505056fe63616c6c65722d69732d6e6f742d7468652d676f7665726e6f72000000000000a26469706673582212206563c0403c9c81451e1ae05fe03ff2fe4984fd0a26ef8326c5cc9de89de6ee2a64736f6c63430008090033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a80452000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f000000000000000000000000000000000000000000000000000000000000000600000000000000000000000008780fb7e580e492c1935bee4fa5920b94aa95da000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd52000000000000000000000000000000000000000000000000000000000000006400000000000000000000000080704acdf97723963263c78f861f091ad04f46e2000000000000000000000000229f19942612a8dbdec3643cb23f88685ccd56a50000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000001d436f6e766578466f72467261785f657573646672617862705f55534443000000
-----Decoded View---------------
Arg [0] : pool_ (address): 0xa8b607Aa09B6A2E306F93e74c282Fb13f6A80452
Arg [1] : crvPool_ (address): 0xAEda92e6A3B1028edc139A4ae56Ec881f3064D4F
Arg [2] : curvePoolType_ (uint8): 6
Arg [3] : depositZap_ (address): 0x08780fb7E580e492c1935bEe4fA5920b94AA95Da
Arg [4] : crvToken_ (address): 0xD533a949740bb3306d119CC777fa900bA034cd52
Arg [5] : crvSlippage_ (uint256): 100
Arg [6] : masterOracle_ (address): 0x80704Acdf97723963263c78F861F091ad04F46E2
Arg [7] : swapper_ (address): 0x229f19942612A8dbdec3643CB23F88685CCd56A5
Arg [8] : collateralIdx_ (uint256): 2
Arg [9] : convexPoolId_ (uint256): 44
Arg [10] : name_ (string): ConvexForFrax_eusdfraxbp_USDC
-----Encoded View---------------
13 Constructor Arguments found :
Arg [0] : 000000000000000000000000a8b607aa09b6a2e306f93e74c282fb13f6a80452
Arg [1] : 000000000000000000000000aeda92e6a3b1028edc139a4ae56ec881f3064d4f
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [3] : 00000000000000000000000008780fb7e580e492c1935bee4fa5920b94aa95da
Arg [4] : 000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd52
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [6] : 00000000000000000000000080704acdf97723963263c78f861f091ad04f46e2
Arg [7] : 000000000000000000000000229f19942612a8dbdec3643cb23f88685ccd56a5
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [9] : 000000000000000000000000000000000000000000000000000000000000002c
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [11] : 000000000000000000000000000000000000000000000000000000000000001d
Arg [12] : 436f6e766578466f72467261785f657573646672617862705f55534443000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.