More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
20732517 | 37 days ago | 0.00596369 ETH | ||||
20732517 | 37 days ago | 0.00596369 ETH | ||||
20625070 | 52 days ago | 0.00129529 ETH | ||||
20625070 | 52 days ago | 0.00129529 ETH | ||||
19873352 | 157 days ago | 0.00068666 ETH | ||||
19873352 | 157 days ago | 0.00068666 ETH | ||||
19595330 | 196 days ago | 0.5273734 ETH | ||||
19595330 | 196 days ago | 0.5273734 ETH | ||||
19338290 | 232 days ago | 0.01363207 ETH | ||||
19293728 | 238 days ago | 0.01363207 ETH | ||||
19111976 | 264 days ago | 0.00423512 ETH | ||||
19111976 | 264 days ago | 0.00423512 ETH | ||||
19004911 | 279 days ago | 0.00318814 ETH | ||||
18980699 | 282 days ago | 0.00318814 ETH | ||||
18820528 | 305 days ago | 1.3465372 ETH | ||||
18820528 | 305 days ago | 1.3465372 ETH | ||||
18714031 | 320 days ago | 2.24625439 ETH | ||||
18714031 | 320 days ago | 2.24625439 ETH | ||||
17826946 | 444 days ago | 0.01706813 ETH | ||||
17826946 | 444 days ago | 0.01706813 ETH | ||||
17506134 | 489 days ago | 0.73130679 ETH | ||||
17506134 | 489 days ago | 0.73130679 ETH | ||||
17399622 | 504 days ago | 0.14169547 ETH | ||||
17399622 | 504 days ago | 0.1234966 ETH | ||||
17309458 | 517 days ago | 0.01819886 ETH |
Loading...
Loading
Contract Name:
Strategy
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2022-07-19 */ // SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.6.12; pragma experimental ABIEncoderV2; // Global Enums and Structs struct StrategyParams { uint256 performanceFee; uint256 activation; uint256 debtRatio; uint256 minDebtPerHarvest; uint256 maxDebtPerHarvest; uint256 lastReport; uint256 totalDebt; uint256 totalGain; uint256 totalLoss; } // Part: IBaseFee interface IBaseFee { function isCurrentBaseFeeAcceptable() external view returns (bool); } // Part: IBaseFeeOracle interface IBaseFeeOracle { function basefee_global() external view returns (uint256); } // Part: IPriceFeed interface IPriceFeed { // --- Events --- event LastGoodPriceUpdated(uint256 _lastGoodPrice); // --- Function --- function fetchPrice() external returns (uint256); function lastGoodPrice() external view returns (uint256); } // Part: IStabilityPool /* * The Stability Pool holds LUSD tokens deposited by Stability Pool depositors. * * When a trove is liquidated, then depending on system conditions, some of its LUSD debt gets offset with * LUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of LUSD tokens in the Stability Pool is burned. * * Thus, a liquidation causes each depositor to receive a LUSD loss, in proportion to their deposit as a share of total deposits. * They also receive an ETH gain, as the ETH collateral of the liquidated trove is distributed among Stability depositors, * in the same proportion. * * When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40% * of the total LUSD in the Stability Pool, depletes 40% of each deposit. * * A deposit that has experienced a series of liquidations is termed a "compounded deposit": each liquidation depletes the deposit, * multiplying it by some factor in range ]0,1[ * * Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / ETH gain derivations: * https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf * * --- LQTY ISSUANCE TO STABILITY POOL DEPOSITORS --- * * An LQTY issuance event occurs at every deposit operation, and every liquidation. * * Each deposit is tagged with the address of the front end through which it was made. * * All deposits earn a share of the issued LQTY in proportion to the deposit as a share of total deposits. The LQTY earned * by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate. * * Please see the system Readme for an overview: * https://github.com/liquity/dev/blob/main/README.md#lqty-issuance-to-stability-providers */ interface IStabilityPool { // --- Events --- event StabilityPoolETHBalanceUpdated(uint _newBalance); event StabilityPoolLUSDBalanceUpdated(uint _newBalance); event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress); event TroveManagerAddressChanged(address _newTroveManagerAddress); event ActivePoolAddressChanged(address _newActivePoolAddress); event DefaultPoolAddressChanged(address _newDefaultPoolAddress); event LUSDTokenAddressChanged(address _newLUSDTokenAddress); event SortedTrovesAddressChanged(address _newSortedTrovesAddress); event PriceFeedAddressChanged(address _newPriceFeedAddress); event CommunityIssuanceAddressChanged(address _newCommunityIssuanceAddress); event P_Updated(uint _P); event S_Updated(uint _S, uint128 _epoch, uint128 _scale); event G_Updated(uint _G, uint128 _epoch, uint128 _scale); event EpochUpdated(uint128 _currentEpoch); event ScaleUpdated(uint128 _currentScale); event FrontEndRegistered(address indexed _frontEnd, uint _kickbackRate); event FrontEndTagSet(address indexed _depositor, address indexed _frontEnd); event DepositSnapshotUpdated(address indexed _depositor, uint _P, uint _S, uint _G); event FrontEndSnapshotUpdated(address indexed _frontEnd, uint _P, uint _G); event UserDepositChanged(address indexed _depositor, uint _newDeposit); event FrontEndStakeChanged(address indexed _frontEnd, uint _newFrontEndStake, address _depositor); event ETHGainWithdrawn(address indexed _depositor, uint _ETH, uint _LUSDLoss); event LQTYPaidToDepositor(address indexed _depositor, uint _LQTY); event LQTYPaidToFrontEnd(address indexed _frontEnd, uint _LQTY); event EtherSent(address _to, uint _amount); // --- Functions --- /* * Called only once on init, to set addresses of other Liquity contracts * Callable only by owner, renounces ownership at the end */ function setAddresses( address _borrowerOperationsAddress, address _troveManagerAddress, address _activePoolAddress, address _lusdTokenAddress, address _sortedTrovesAddress, address _priceFeedAddress, address _communityIssuanceAddress ) external; /* * Initial checks: * - Frontend is registered or zero address * - Sender is not a registered frontend * - _amount is not zero * --- * - Triggers a LQTY issuance, based on time passed since the last issuance. The LQTY issuance is shared between *all* depositors and front ends * - Tags the deposit with the provided front end tag param, if it's a new deposit * - Sends depositor's accumulated gains (LQTY, ETH) to depositor * - Sends the tagged front end's accumulated LQTY gains to the tagged front end * - Increases deposit and tagged front end's stake, and takes new snapshots for each. */ function provideToSP(uint _amount, address _frontEndTag) external; /* * Initial checks: * - _amount is zero or there are no under collateralized troves left in the system * - User has a non zero deposit * --- * - Triggers a LQTY issuance, based on time passed since the last issuance. The LQTY issuance is shared between *all* depositors and front ends * - Removes the deposit's front end tag if it is a full withdrawal * - Sends all depositor's accumulated gains (LQTY, ETH) to depositor * - Sends the tagged front end's accumulated LQTY gains to the tagged front end * - Decreases deposit and tagged front end's stake, and takes new snapshots for each. * * If _amount > userDeposit, the user withdraws all of their compounded deposit. */ function withdrawFromSP(uint _amount) external; /* * Initial checks: * - User has a non zero deposit * - User has an open trove * - User has some ETH gain * --- * - Triggers a LQTY issuance, based on time passed since the last issuance. The LQTY issuance is shared between *all* depositors and front ends * - Sends all depositor's LQTY gain to depositor * - Sends all tagged front end's LQTY gain to the tagged front end * - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove * - Leaves their compounded deposit in the Stability Pool * - Updates snapshots for deposit and tagged front end stake */ function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external; /* * Initial checks: * - Frontend (sender) not already registered * - User (sender) has no deposit * - _kickbackRate is in the range [0, 100%] * --- * Front end makes a one-time selection of kickback rate upon registering */ function registerFrontEnd(uint _kickbackRate) external; /* * Initial checks: * - Caller is TroveManager * --- * Cancels out the specified debt against the LUSD contained in the Stability Pool (as far as possible) * and transfers the Trove's ETH collateral from ActivePool to StabilityPool. * Only called by liquidation functions in the TroveManager. */ function offset(uint _debt, uint _coll) external; /* * Returns the total amount of ETH held by the pool, accounted in an internal variable instead of `balance`, * to exclude edge cases like ETH received from a self-destruct. */ function getETH() external view returns (uint); /* * Returns LUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset. */ function getTotalLUSDDeposits() external view returns (uint); /* * Calculates the ETH gain earned by the deposit since its last snapshots were taken. */ function getDepositorETHGain(address _depositor) external view returns (uint); /* * Calculate the LQTY gain earned by a deposit since its last snapshots were taken. * If not tagged with a front end, the depositor gets a 100% cut of what their deposit earned. * Otherwise, their cut of the deposit's earnings is equal to the kickbackRate, set by the front end through * which they made their deposit. */ function getDepositorLQTYGain(address _depositor) external view returns (uint); /* * Return the LQTY gain earned by the front end. */ function getFrontEndLQTYGain(address _frontEnd) external view returns (uint); /* * Return the user's compounded deposit. */ function getCompoundedLUSDDeposit(address _depositor) external view returns (uint); /* * Return the front end's compounded stake. * * The front end's compounded stake is equal to the sum of its depositors' compounded deposits. */ function getCompoundedFrontEndStake(address _frontEnd) external view returns (uint); /* * Fallback function * Only callable by Active Pool, it just accounts for ETH received * receive() external payable; */ } // Part: IStableSwapExchange interface IStableSwapExchange { function get_dy_underlying( int128 i, int128 j, uint256 dx ) external view returns (uint256); function exchange_underlying( int128 i, int128 j, uint256 dx, uint256 min_dy ) external returns (uint256); } // Part: IUniswapV3SwapCallback /// @title Callback for IUniswapV3PoolActions#swap /// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface interface IUniswapV3SwapCallback { /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. /// @dev In the implementation you must pay the pool tokens owed for the swap. /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call function uniswapV3SwapCallback( int256 amount0Delta, int256 amount1Delta, bytes calldata data ) external; } // Part: OpenZeppelin/[email protected]/Address /** * @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) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @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"); return _functionCallWithValue(target, data, value, errorMessage); } function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); 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); } } } } // Part: OpenZeppelin/[email protected]/IERC20 /** * @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); } // Part: OpenZeppelin/[email protected]/Math /** * @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); } } // Part: OpenZeppelin/[email protected]/SafeMath /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when 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. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // Part: yearn/[email protected]/HealthCheck interface HealthCheck { function check( uint256 profit, uint256 loss, uint256 debtPayment, uint256 debtOutstanding, uint256 totalDebt ) external view returns (bool); } // Part: ISwapRouter /// @title Router token swapping functionality /// @notice Functions for swapping tokens via Uniswap V3 interface ISwapRouter is IUniswapV3SwapCallback { struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; } /// @notice Swaps `amountIn` of one token for as much as possible of another token /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata /// @return amountOut The amount of the received token function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); struct ExactInputParams { bytes path; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; } /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata /// @return amountOut The amount of the received token function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); struct ExactOutputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; uint160 sqrtPriceLimitX96; } /// @notice Swaps as little as possible of one token for `amountOut` of another token /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata /// @return amountIn The amount of the input token function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); struct ExactOutputParams { bytes path; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; } /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata /// @return amountIn The amount of the input token function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); // Taken from https://soliditydeveloper.com/uniswap3 // Manually added to the interface function refundETH() external payable; } // Part: IWETH9 interface IWETH9 is IERC20 { function deposit() external payable; function withdraw(uint256 wad) external; } // Part: OpenZeppelin/[email protected]/SafeERC20 /** * @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 SafeMath for uint256; 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).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _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"); } } } // Part: yearn/[email protected]/VaultAPI interface VaultAPI is IERC20 { function name() external view returns (string calldata); function symbol() external view returns (string calldata); function decimals() external view returns (uint256); function apiVersion() external pure returns (string memory); function permit( address owner, address spender, uint256 amount, uint256 expiry, bytes calldata signature ) external returns (bool); // NOTE: Vyper produces multiple signatures for a given function with "default" args function deposit() external returns (uint256); function deposit(uint256 amount) external returns (uint256); function deposit(uint256 amount, address recipient) external returns (uint256); // NOTE: Vyper produces multiple signatures for a given function with "default" args function withdraw() external returns (uint256); function withdraw(uint256 maxShares) external returns (uint256); function withdraw(uint256 maxShares, address recipient) external returns (uint256); function token() external view returns (address); function strategies(address _strategy) external view returns (StrategyParams memory); function pricePerShare() external view returns (uint256); function totalAssets() external view returns (uint256); function depositLimit() external view returns (uint256); function maxAvailableShares() external view returns (uint256); /** * View how much the Vault would increase this Strategy's borrow limit, * based on its present performance (since its last report). Can be used to * determine expectedReturn in your Strategy. */ function creditAvailable() external view returns (uint256); /** * View how much the Vault would like to pull back from the Strategy, * based on its present performance (since its last report). Can be used to * determine expectedReturn in your Strategy. */ function debtOutstanding() external view returns (uint256); /** * View how much the Vault expect this Strategy to return at the current * block, based on its present performance (since its last report). Can be * used to determine expectedReturn in your Strategy. */ function expectedReturn() external view returns (uint256); /** * This is the main contact point where the Strategy interacts with the * Vault. It is critical that this call is handled as intended by the * Strategy. Therefore, this function will be called by BaseStrategy to * make sure the integration is correct. */ function report( uint256 _gain, uint256 _loss, uint256 _debtPayment ) external returns (uint256); /** * This function should only be used in the scenario where the Strategy is * being retired but no migration of the positions are possible, or in the * extreme scenario that the Strategy needs to be put into "Emergency Exit" * mode in order for it to exit as quickly as possible. The latter scenario * could be for any reason that is considered "critical" that the Strategy * exits its position as fast as possible, such as a sudden change in * market conditions leading to losses, or an imminent failure in an * external dependency. */ function revokeStrategy() external; /** * View the governance address of the Vault to assert privileged functions * can only be called by governance. The Strategy serves the Vault, so it * is subject to governance defined by the Vault. */ function governance() external view returns (address); /** * View the management address of the Vault to assert privileged functions * can only be called by management. The Strategy serves the Vault, so it * is subject to management defined by the Vault. */ function management() external view returns (address); /** * View the guardian address of the Vault to assert privileged functions * can only be called by guardian. The Strategy serves the Vault, so it * is subject to guardian defined by the Vault. */ function guardian() external view returns (address); } // Part: yearn/[email protected]/BaseStrategy /** * @title Yearn Base Strategy * @author yearn.finance * @notice * BaseStrategy implements all of the required functionality to interoperate * closely with the Vault contract. This contract should be inherited and the * abstract methods implemented to adapt the Strategy to the particular needs * it has to create a return. * * Of special interest is the relationship between `harvest()` and * `vault.report()'. `harvest()` may be called simply because enough time has * elapsed since the last report, and not because any funds need to be moved * or positions adjusted. This is critical so that the Vault may maintain an * accurate picture of the Strategy's performance. See `vault.report()`, * `harvest()`, and `harvestTrigger()` for further details. */ abstract contract BaseStrategy { using SafeMath for uint256; using SafeERC20 for IERC20; string public metadataURI; // health checks bool public doHealthCheck; address public healthCheck; /** * @notice * Used to track which version of `StrategyAPI` this Strategy * implements. * @dev The Strategy's version must match the Vault's `API_VERSION`. * @return A string which holds the current API version of this contract. */ function apiVersion() public pure returns (string memory) { return "0.4.3"; } /** * @notice This Strategy's name. * @dev * You can use this field to manage the "version" of this Strategy, e.g. * `StrategySomethingOrOtherV1`. However, "API Version" is managed by * `apiVersion()` function above. * @return This Strategy's name. */ function name() external view virtual returns (string memory); /** * @notice * The amount (priced in want) of the total assets managed by this strategy should not count * towards Yearn's TVL calculations. * @dev * You can override this field to set it to a non-zero value if some of the assets of this * Strategy is somehow delegated inside another part of of Yearn's ecosystem e.g. another Vault. * Note that this value must be strictly less than or equal to the amount provided by * `estimatedTotalAssets()` below, as the TVL calc will be total assets minus delegated assets. * Also note that this value is used to determine the total assets under management by this * strategy, for the purposes of computing the management fee in `Vault` * @return * The amount of assets this strategy manages that should not be included in Yearn's Total Value * Locked (TVL) calculation across it's ecosystem. */ function delegatedAssets() external view virtual returns (uint256) { return 0; } VaultAPI public vault; address public strategist; address public rewards; address public keeper; IERC20 public want; // So indexers can keep track of this event Harvested(uint256 profit, uint256 loss, uint256 debtPayment, uint256 debtOutstanding); event UpdatedStrategist(address newStrategist); event UpdatedKeeper(address newKeeper); event UpdatedRewards(address rewards); event UpdatedMinReportDelay(uint256 delay); event UpdatedMaxReportDelay(uint256 delay); event UpdatedProfitFactor(uint256 profitFactor); event UpdatedDebtThreshold(uint256 debtThreshold); event EmergencyExitEnabled(); event UpdatedMetadataURI(string metadataURI); // The minimum number of seconds between harvest calls. See // `setMinReportDelay()` for more details. uint256 public minReportDelay; // The maximum number of seconds between harvest calls. See // `setMaxReportDelay()` for more details. uint256 public maxReportDelay; // The minimum multiple that `callCost` must be above the credit/profit to // be "justifiable". See `setProfitFactor()` for more details. uint256 public profitFactor; // Use this to adjust the threshold at which running a debt causes a // harvest trigger. See `setDebtThreshold()` for more details. uint256 public debtThreshold; // See note on `setEmergencyExit()`. bool public emergencyExit; // modifiers modifier onlyAuthorized() { require(msg.sender == strategist || msg.sender == governance(), "!authorized"); _; } modifier onlyEmergencyAuthorized() { require( msg.sender == strategist || msg.sender == governance() || msg.sender == vault.guardian() || msg.sender == vault.management(), "!authorized" ); _; } modifier onlyStrategist() { require(msg.sender == strategist, "!strategist"); _; } modifier onlyGovernance() { require(msg.sender == governance(), "!authorized"); _; } modifier onlyKeepers() { require( msg.sender == keeper || msg.sender == strategist || msg.sender == governance() || msg.sender == vault.guardian() || msg.sender == vault.management(), "!authorized" ); _; } modifier onlyVaultManagers() { require(msg.sender == vault.management() || msg.sender == governance(), "!authorized"); _; } constructor(address _vault) public { _initialize(_vault, msg.sender, msg.sender, msg.sender); } /** * @notice * Initializes the Strategy, this is called only once, when the * contract is deployed. * @dev `_vault` should implement `VaultAPI`. * @param _vault The address of the Vault responsible for this Strategy. * @param _strategist The address to assign as `strategist`. * The strategist is able to change the reward address * @param _rewards The address to use for pulling rewards. * @param _keeper The adddress of the _keeper. _keeper * can harvest and tend a strategy. */ function _initialize( address _vault, address _strategist, address _rewards, address _keeper ) internal { require(address(want) == address(0), "Strategy already initialized"); vault = VaultAPI(_vault); want = IERC20(vault.token()); want.safeApprove(_vault, uint256(-1)); // Give Vault unlimited access (might save gas) strategist = _strategist; rewards = _rewards; keeper = _keeper; // initialize variables minReportDelay = 0; maxReportDelay = 86400; profitFactor = 100; debtThreshold = 0; vault.approve(rewards, uint256(-1)); // Allow rewards to be pulled } function setHealthCheck(address _healthCheck) external onlyVaultManagers { healthCheck = _healthCheck; } function setDoHealthCheck(bool _doHealthCheck) external onlyVaultManagers { doHealthCheck = _doHealthCheck; } /** * @notice * Used to change `strategist`. * * This may only be called by governance or the existing strategist. * @param _strategist The new address to assign as `strategist`. */ function setStrategist(address _strategist) external onlyAuthorized { require(_strategist != address(0)); strategist = _strategist; emit UpdatedStrategist(_strategist); } /** * @notice * Used to change `keeper`. * * `keeper` is the only address that may call `tend()` or `harvest()`, * other than `governance()` or `strategist`. However, unlike * `governance()` or `strategist`, `keeper` may *only* call `tend()` * and `harvest()`, and no other authorized functions, following the * principle of least privilege. * * This may only be called by governance or the strategist. * @param _keeper The new address to assign as `keeper`. */ function setKeeper(address _keeper) external onlyAuthorized { require(_keeper != address(0)); keeper = _keeper; emit UpdatedKeeper(_keeper); } /** * @notice * Used to change `rewards`. EOA or smart contract which has the permission * to pull rewards from the vault. * * This may only be called by the strategist. * @param _rewards The address to use for pulling rewards. */ function setRewards(address _rewards) external onlyStrategist { require(_rewards != address(0)); vault.approve(rewards, 0); rewards = _rewards; vault.approve(rewards, uint256(-1)); emit UpdatedRewards(_rewards); } /** * @notice * Used to change `minReportDelay`. `minReportDelay` is the minimum number * of blocks that should pass for `harvest()` to be called. * * For external keepers (such as the Keep3r network), this is the minimum * time between jobs to wait. (see `harvestTrigger()` * for more details.) * * This may only be called by governance or the strategist. * @param _delay The minimum number of seconds to wait between harvests. */ function setMinReportDelay(uint256 _delay) external onlyAuthorized { minReportDelay = _delay; emit UpdatedMinReportDelay(_delay); } /** * @notice * Used to change `maxReportDelay`. `maxReportDelay` is the maximum number * of blocks that should pass for `harvest()` to be called. * * For external keepers (such as the Keep3r network), this is the maximum * time between jobs to wait. (see `harvestTrigger()` * for more details.) * * This may only be called by governance or the strategist. * @param _delay The maximum number of seconds to wait between harvests. */ function setMaxReportDelay(uint256 _delay) external onlyAuthorized { maxReportDelay = _delay; emit UpdatedMaxReportDelay(_delay); } /** * @notice * Used to change `profitFactor`. `profitFactor` is used to determine * if it's worthwhile to harvest, given gas costs. (See `harvestTrigger()` * for more details.) * * This may only be called by governance or the strategist. * @param _profitFactor A ratio to multiply anticipated * `harvest()` gas cost against. */ function setProfitFactor(uint256 _profitFactor) external onlyAuthorized { profitFactor = _profitFactor; emit UpdatedProfitFactor(_profitFactor); } /** * @notice * Sets how far the Strategy can go into loss without a harvest and report * being required. * * By default this is 0, meaning any losses would cause a harvest which * will subsequently report the loss to the Vault for tracking. (See * `harvestTrigger()` for more details.) * * This may only be called by governance or the strategist. * @param _debtThreshold How big of a loss this Strategy may carry without * being required to report to the Vault. */ function setDebtThreshold(uint256 _debtThreshold) external onlyAuthorized { debtThreshold = _debtThreshold; emit UpdatedDebtThreshold(_debtThreshold); } /** * @notice * Used to change `metadataURI`. `metadataURI` is used to store the URI * of the file describing the strategy. * * This may only be called by governance or the strategist. * @param _metadataURI The URI that describe the strategy. */ function setMetadataURI(string calldata _metadataURI) external onlyAuthorized { metadataURI = _metadataURI; emit UpdatedMetadataURI(_metadataURI); } /** * Resolve governance address from Vault contract, used to make assertions * on protected functions in the Strategy. */ function governance() internal view returns (address) { return vault.governance(); } /** * @notice * Provide an accurate conversion from `_amtInWei` (denominated in wei) * to `want` (using the native decimal characteristics of `want`). * @dev * Care must be taken when working with decimals to assure that the conversion * is compatible. As an example: * * given 1e17 wei (0.1 ETH) as input, and want is USDC (6 decimals), * with USDC/ETH = 1800, this should give back 1800000000 (180 USDC) * * @param _amtInWei The amount (in wei/1e-18 ETH) to convert to `want` * @return The amount in `want` of `_amtInEth` converted to `want` **/ function ethToWant(uint256 _amtInWei) public view virtual returns (uint256); /** * @notice * Provide an accurate estimate for the total amount of assets * (principle + return) that this Strategy is currently managing, * denominated in terms of `want` tokens. * * This total should be "realizable" e.g. the total value that could * *actually* be obtained from this Strategy if it were to divest its * entire position based on current on-chain conditions. * @dev * Care must be taken in using this function, since it relies on external * systems, which could be manipulated by the attacker to give an inflated * (or reduced) value produced by this function, based on current on-chain * conditions (e.g. this function is possible to influence through * flashloan attacks, oracle manipulations, or other DeFi attack * mechanisms). * * It is up to governance to use this function to correctly order this * Strategy relative to its peers in the withdrawal queue to minimize * losses for the Vault based on sudden withdrawals. This value should be * higher than the total debt of the Strategy and higher than its expected * value to be "safe". * @return The estimated total assets in this Strategy. */ function estimatedTotalAssets() public view virtual returns (uint256); /* * @notice * Provide an indication of whether this strategy is currently "active" * in that it is managing an active position, or will manage a position in * the future. This should correlate to `harvest()` activity, so that Harvest * events can be tracked externally by indexing agents. * @return True if the strategy is actively managing a position. */ function isActive() public view returns (bool) { return vault.strategies(address(this)).debtRatio > 0 || estimatedTotalAssets() > 0; } /** * Perform any Strategy unwinding or other calls necessary to capture the * "free return" this Strategy has generated since the last time its core * position(s) were adjusted. Examples include unwrapping extra rewards. * This call is only used during "normal operation" of a Strategy, and * should be optimized to minimize losses as much as possible. * * This method returns any realized profits and/or realized losses * incurred, and should return the total amounts of profits/losses/debt * payments (in `want` tokens) for the Vault's accounting (e.g. * `want.balanceOf(this) >= _debtPayment + _profit`). * * `_debtOutstanding` will be 0 if the Strategy is not past the configured * debt limit, otherwise its value will be how far past the debt limit * the Strategy is. The Strategy's debt limit is configured in the Vault. * * NOTE: `_debtPayment` should be less than or equal to `_debtOutstanding`. * It is okay for it to be less than `_debtOutstanding`, as that * should only used as a guide for how much is left to pay back. * Payments should be made to minimize loss from slippage, debt, * withdrawal fees, etc. * * See `vault.debtOutstanding()`. */ function prepareReturn(uint256 _debtOutstanding) internal virtual returns ( uint256 _profit, uint256 _loss, uint256 _debtPayment ); /** * Perform any adjustments to the core position(s) of this Strategy given * what change the Vault made in the "investable capital" available to the * Strategy. Note that all "free capital" in the Strategy after the report * was made is available for reinvestment. Also note that this number * could be 0, and you should handle that scenario accordingly. * * See comments regarding `_debtOutstanding` on `prepareReturn()`. */ function adjustPosition(uint256 _debtOutstanding) internal virtual; /** * Liquidate up to `_amountNeeded` of `want` of this strategy's positions, * irregardless of slippage. Any excess will be re-invested with `adjustPosition()`. * This function should return the amount of `want` tokens made available by the * liquidation. If there is a difference between them, `_loss` indicates whether the * difference is due to a realized loss, or if there is some other sitution at play * (e.g. locked funds) where the amount made available is less than what is needed. * * NOTE: The invariant `_liquidatedAmount + _loss <= _amountNeeded` should always be maintained */ function liquidatePosition(uint256 _amountNeeded) internal virtual returns (uint256 _liquidatedAmount, uint256 _loss); /** * Liquidate everything and returns the amount that got freed. * This function is used during emergency exit instead of `prepareReturn()` to * liquidate all of the Strategy's positions back to the Vault. */ function liquidateAllPositions() internal virtual returns (uint256 _amountFreed); /** * @notice * Provide a signal to the keeper that `tend()` should be called. The * keeper will provide the estimated gas cost that they would pay to call * `tend()`, and this function should use that estimate to make a * determination if calling it is "worth it" for the keeper. This is not * the only consideration into issuing this trigger, for example if the * position would be negatively affected if `tend()` is not called * shortly, then this can return `true` even if the keeper might be * "at a loss" (keepers are always reimbursed by Yearn). * @dev * `callCostInWei` must be priced in terms of `wei` (1e-18 ETH). * * This call and `harvestTrigger()` should never return `true` at the same * time. * @param callCostInWei The keeper's estimated gas cost to call `tend()` (in wei). * @return `true` if `tend()` should be called, `false` otherwise. */ function tendTrigger(uint256 callCostInWei) public view virtual returns (bool) { // We usually don't need tend, but if there are positions that need // active maintainence, overriding this function is how you would // signal for that. // If your implementation uses the cost of the call in want, you can // use uint256 callCost = ethToWant(callCostInWei); return false; } /** * @notice * Adjust the Strategy's position. The purpose of tending isn't to * realize gains, but to maximize yield by reinvesting any returns. * * See comments on `adjustPosition()`. * * This may only be called by governance, the strategist, or the keeper. */ function tend() external onlyKeepers { // Don't take profits with this call, but adjust for better gains adjustPosition(vault.debtOutstanding()); } /** * @notice * Provide a signal to the keeper that `harvest()` should be called. The * keeper will provide the estimated gas cost that they would pay to call * `harvest()`, and this function should use that estimate to make a * determination if calling it is "worth it" for the keeper. This is not * the only consideration into issuing this trigger, for example if the * position would be negatively affected if `harvest()` is not called * shortly, then this can return `true` even if the keeper might be "at a * loss" (keepers are always reimbursed by Yearn). * @dev * `callCostInWei` must be priced in terms of `wei` (1e-18 ETH). * * This call and `tendTrigger` should never return `true` at the * same time. * * See `min/maxReportDelay`, `profitFactor`, `debtThreshold` to adjust the * strategist-controlled parameters that will influence whether this call * returns `true` or not. These parameters will be used in conjunction * with the parameters reported to the Vault (see `params`) to determine * if calling `harvest()` is merited. * * It is expected that an external system will check `harvestTrigger()`. * This could be a script run off a desktop or cloud bot (e.g. * https://github.com/iearn-finance/yearn-vaults/blob/main/scripts/keep.py), * or via an integration with the Keep3r network (e.g. * https://github.com/Macarse/GenericKeep3rV2/blob/master/contracts/keep3r/GenericKeep3rV2.sol). * @param callCostInWei The keeper's estimated gas cost to call `harvest()` (in wei). * @return `true` if `harvest()` should be called, `false` otherwise. */ function harvestTrigger(uint256 callCostInWei) public view virtual returns (bool) { uint256 callCost = ethToWant(callCostInWei); StrategyParams memory params = vault.strategies(address(this)); // Should not trigger if Strategy is not activated if (params.activation == 0) return false; // Should not trigger if we haven't waited long enough since previous harvest if (block.timestamp.sub(params.lastReport) < minReportDelay) return false; // Should trigger if hasn't been called in a while if (block.timestamp.sub(params.lastReport) >= maxReportDelay) return true; // If some amount is owed, pay it back // NOTE: Since debt is based on deposits, it makes sense to guard against large // changes to the value from triggering a harvest directly through user // behavior. This should ensure reasonable resistance to manipulation // from user-initiated withdrawals as the outstanding debt fluctuates. uint256 outstanding = vault.debtOutstanding(); if (outstanding > debtThreshold) return true; // Check for profits and losses uint256 total = estimatedTotalAssets(); // Trigger if we have a loss to report if (total.add(debtThreshold) < params.totalDebt) return true; uint256 profit = 0; if (total > params.totalDebt) profit = total.sub(params.totalDebt); // We've earned a profit! // Otherwise, only trigger if it "makes sense" economically (gas cost // is <N% of value moved) uint256 credit = vault.creditAvailable(); return (profitFactor.mul(callCost) < credit.add(profit)); } /** * @notice * Harvests the Strategy, recognizing any profits or losses and adjusting * the Strategy's position. * * In the rare case the Strategy is in emergency shutdown, this will exit * the Strategy's position. * * This may only be called by governance, the strategist, or the keeper. * @dev * When `harvest()` is called, the Strategy reports to the Vault (via * `vault.report()`), so in some cases `harvest()` must be called in order * to take in profits, to borrow newly available funds from the Vault, or * otherwise adjust its position. In other cases `harvest()` must be * called to report to the Vault on the Strategy's position, especially if * any losses have occurred. */ function harvest() external onlyKeepers { uint256 profit = 0; uint256 loss = 0; uint256 debtOutstanding = vault.debtOutstanding(); uint256 debtPayment = 0; if (emergencyExit) { // Free up as much capital as possible uint256 amountFreed = liquidateAllPositions(); if (amountFreed < debtOutstanding) { loss = debtOutstanding.sub(amountFreed); } else if (amountFreed > debtOutstanding) { profit = amountFreed.sub(debtOutstanding); } debtPayment = debtOutstanding.sub(loss); } else { // Free up returns for Vault to pull (profit, loss, debtPayment) = prepareReturn(debtOutstanding); } // Allow Vault to take up to the "harvested" balance of this contract, // which is the amount it has earned since the last time it reported to // the Vault. uint256 totalDebt = vault.strategies(address(this)).totalDebt; debtOutstanding = vault.report(profit, loss, debtPayment); // Check if free returns are left, and re-invest them adjustPosition(debtOutstanding); // call healthCheck contract if (doHealthCheck && healthCheck != address(0)) { require(HealthCheck(healthCheck).check(profit, loss, debtPayment, debtOutstanding, totalDebt), "!healthcheck"); } else { doHealthCheck = true; } emit Harvested(profit, loss, debtPayment, debtOutstanding); } /** * @notice * Withdraws `_amountNeeded` to `vault`. * * This may only be called by the Vault. * @param _amountNeeded How much `want` to withdraw. * @return _loss Any realized losses */ function withdraw(uint256 _amountNeeded) external returns (uint256 _loss) { require(msg.sender == address(vault), "!vault"); // Liquidate as much as possible to `want`, up to `_amountNeeded` uint256 amountFreed; (amountFreed, _loss) = liquidatePosition(_amountNeeded); // Send it directly back (NOTE: Using `msg.sender` saves some gas here) want.safeTransfer(msg.sender, amountFreed); // NOTE: Reinvest anything leftover on next `tend`/`harvest` } /** * Do anything necessary to prepare this Strategy for migration, such as * transferring any reserve or LP tokens, CDPs, or other tokens or stores of * value. */ function prepareMigration(address _newStrategy) internal virtual; /** * @notice * Transfers all `want` from this Strategy to `_newStrategy`. * * This may only be called by the Vault. * @dev * The new Strategy's Vault must be the same as this Strategy's Vault. * The migration process should be carefully performed to make sure all * the assets are migrated to the new address, which should have never * interacted with the vault before. * @param _newStrategy The Strategy to migrate to. */ function migrate(address _newStrategy) external { require(msg.sender == address(vault)); require(BaseStrategy(_newStrategy).vault() == vault); prepareMigration(_newStrategy); want.safeTransfer(_newStrategy, want.balanceOf(address(this))); } /** * @notice * Activates emergency exit. Once activated, the Strategy will exit its * position upon the next harvest, depositing all funds into the Vault as * quickly as is reasonable given on-chain conditions. * * This may only be called by governance or the strategist. * @dev * See `vault.setEmergencyShutdown()` and `harvest()` for further details. */ function setEmergencyExit() external onlyEmergencyAuthorized { emergencyExit = true; vault.revokeStrategy(); emit EmergencyExitEnabled(); } /** * Override this to add all tokens/tokenized positions this contract * manages on a *persistent* basis (e.g. not just for swapping back to * want ephemerally). * * NOTE: Do *not* include `want`, already included in `sweep` below. * * Example: * ``` * function protectedTokens() internal override view returns (address[] memory) { * address[] memory protected = new address[](3); * protected[0] = tokenA; * protected[1] = tokenB; * protected[2] = tokenC; * return protected; * } * ``` */ function protectedTokens() internal view virtual returns (address[] memory); /** * @notice * Removes tokens from this Strategy that are not the type of tokens * managed by this Strategy. This may be used in case of accidentally * sending the wrong kind of token to this Strategy. * * Tokens will be sent to `governance()`. * * This will fail if an attempt is made to sweep `want`, or any tokens * that are protected by this Strategy. * * This may only be called by governance. * @dev * Implement `protectedTokens()` to specify any additional tokens that * should be protected from sweeping in addition to `want`. * @param _token The token to transfer out of this vault. */ function sweep(address _token) external onlyGovernance { require(_token != address(want), "!want"); require(_token != address(vault), "!shares"); address[] memory _protectedTokens = protectedTokens(); for (uint256 i; i < _protectedTokens.length; i++) require(_token != _protectedTokens[i], "!protected"); IERC20(_token).safeTransfer(governance(), IERC20(_token).balanceOf(address(this))); } } // File: Strategy.sol contract Strategy is BaseStrategy { using SafeERC20 for IERC20; using Address for address; using SafeMath for uint256; // LQTY rewards accrue to Stability Providers who deposit LUSD to the Stability Pool IERC20 internal constant LQTY = IERC20(0x6DEA81C8171D0bA574754EF6F8b412F2Ed88c54D); // Source of liquidity to repay debt from liquidated troves IStabilityPool internal constant stabilityPool = IStabilityPool(0x66017D22b0f8556afDd19FC67041899Eb65a21bb); // Chainlink ETH:USD with Tellor ETH:USD as fallback IPriceFeed internal constant priceFeed = IPriceFeed(0x4c517D4e2C851CA76d7eC94B805269Df0f2201De); // Uniswap v3 router to do LQTY->ETH ISwapRouter internal constant router = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564); // LUSD3CRV Curve Metapool IStableSwapExchange internal constant curvePool = IStableSwapExchange(0xEd279fDD11cA84bEef15AF5D39BB4d4bEE23F0cA); // Wrapped Ether - Used for swaps routing IWETH9 internal constant WETH = IWETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); // DAI - Used for swaps routing IERC20 internal constant DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); // Switch between Uniswap v3 (low liquidity) and Curve to convert DAI->LUSD bool public convertDAItoLUSDonCurve; // Allow changing fees to take advantage of cheaper or more liquid Uniswap pools uint24 public lqtyToEthFee; uint24 public ethToDaiFee; uint24 public daiToLusdFee; // Minimum expected output when swapping // This should be relative to MAX_BPS representing 100% uint256 public minExpectedSwapPercentage; // 100% uint256 internal constant MAX_BPS = 10000; // keeper stuff uint256 public harvestProfitMin; // minimum size that we want to harvest /*** Variables for tend() and tendTrigger() to make sure we are actively swapping ETH out ***/ //Max base fee acceptable for tend. Will be higher than a harvest max due to potential for elevated gas // during volatile periods when this is most needed, but still want to check extreme scenarios uint256 public maxTendBaseFee; //The max amount of ETH should be in relation to the total value of the strat i.e. 100 == 1% uint256 public maxEthPercent; //The absolute max amount of ETH we will allow the strat to hold uint256 public maxEthAmount; //Max eth to sell in one transaction through calimEthAndSell() uint256 public maxEthToSell; constructor(address _vault) public BaseStrategy(_vault) { // Use curve as default route to swap DAI for LUSD convertDAItoLUSDonCurve = true; // Set health check to health.ychad.eth healthCheck = 0xDDCea799fF1699e98EDF118e0629A974Df7DF012; // Set default pools to use on Uniswap lqtyToEthFee = 3000; ethToDaiFee = 3000; daiToLusdFee = 500; // Allow % slippage by default minExpectedSwapPercentage = 9800; //Deploy on expectation of ~1m TVL ~ .1% gain harvestProfitMin = 1_000e18; maxTendBaseFee = 200e9; //Initiall set to 1% maxEthPercent = 100; maxEthAmount = 100e18; //Set to max on deploy and updated later if needed to maxEthToSell = type(uint256).max; } // Strategy should be able to receive ETH receive() external payable {} // ----------------- SETTERS & EXTERNAL CONFIGURATION ----------------- // Allow governance to claim any outstanding ETH balance // This is done to provide additional flexibility since this is ETH and not WETH // so gov cannot sweep it function swallowETH() external onlyGovernance { (bool sent, ) = msg.sender.call{value: address(this).balance}(""); require(sent); // dev: could not send ether to governance } // Allow governance to wrap any outstanding ETH balance function wrapETH() external onlyGovernance { WETH.deposit{value: address(this).balance}(); } // Switch between Uniswap v3 (low liquidity) and Curve to convert DAI->LUSD function setConvertDAItoLUSDonCurve(bool _convertDAItoLUSDonCurve) external onlyEmergencyAuthorized { convertDAItoLUSDonCurve = _convertDAItoLUSDonCurve; } // Take advantage of cheaper Uniswap pools // Setting a non-existent pool will cause the swap operation to revert function setSwapFees( uint24 _lqtyToEthFee, uint24 _ethToDaiFee, uint24 _daiToLusdFee ) external onlyEmergencyAuthorized { lqtyToEthFee = _lqtyToEthFee; ethToDaiFee = _ethToDaiFee; daiToLusdFee = _daiToLusdFee; } // Ideally we would receive fair market value by performing every swap // through Flashbots. However, since we may be swapping capital and not // only profits, it is important to do our best to avoid bad swaps or // sandwiches in case we end up in an uncle block. function setMinExpectedSwapPercentage(uint256 _minExpectedSwapPercentage) external onlyEmergencyAuthorized { minExpectedSwapPercentage = _minExpectedSwapPercentage; } //Change tend triggers and variables based on market conditions function setTendAmounts( uint256 _maxEthPercent, uint256 _maxEthAmount, uint256 _maxEthToSell, uint256 _maxTendBaseFee ) external onlyEmergencyAuthorized { require(_maxEthPercent <= MAX_BPS, "Too Many Bips"); require(_maxEthToSell > 0, "Can't be 0"); maxEthPercent = _maxEthPercent; maxEthAmount = _maxEthAmount; maxEthToSell = _maxEthToSell; maxTendBaseFee = _maxTendBaseFee; } // Min profit to start checking for harvests if gas is good function setHarvestTriggerMin( uint256 _harvestProfitMin ) external onlyEmergencyAuthorized { harvestProfitMin = _harvestProfitMin; } // Wrapper around `provideToSP` to allow forcing a deposit externally // This could be useful to trigger LQTY / ETH transfers without harvesting. // `provideToSP` will revert if not enough funds are provided so no need // to have an additional check. function depositLUSD(uint256 _amount) external onlyEmergencyAuthorized { stabilityPool.provideToSP(_amount, address(0)); } // Wrapper around `withdrawFromSP` to allow forcing a withdrawal externally. // This could be useful to trigger LQTY / ETH transfers without harvesting // or bypassing any scenario where strategy funds are locked (e.g: bad accounting). // `withdrawFromSP` will revert if there are no deposits. If _amount is larger // than the deposit it will return all remaining balance. function withdrawLUSD(uint256 _amount) external onlyEmergencyAuthorized { stabilityPool.withdrawFromSP(_amount); } // ----------------- BASE STRATEGY FUNCTIONS ----------------- function name() external view override returns (string memory) { return "StrategyLiquityStabilityPoolLUSD"; } function estimatedTotalAssets() public view override returns (uint256) { // 1 LUSD = 1 USD *guaranteed* (TM) uint256 daiBalance = DAI.balanceOf(address(this)); uint256 daiToWant = daiBalance > 0 ? curvePool.get_dy_underlying(1, 0, daiBalance) : 0; return totalLUSDBalance().add(daiToWant).add( totalETHBalance().mul(priceFeed.lastGoodPrice()).div(1e18) ); } function prepareReturn(uint256 _debtOutstanding) internal override returns ( uint256 _profit, uint256 _loss, uint256 _debtPayment ) { // How much do we owe to the LUSD vault? uint256 totalDebt = vault.strategies(address(this)).totalDebt; // Claim LQTY/ETH and sell them for more LUSD //This should fail if we can not get enough LUSD due to peg based on slippage tolerance _claimRewards(); // At this point all ETH DAI and LQTY has been converted to LUSD uint256 totalAssetsAfterClaim = totalLUSDBalance(); if (totalAssetsAfterClaim > totalDebt) { _profit = totalAssetsAfterClaim.sub(totalDebt); _loss = 0; } else { _profit = 0; _loss = totalDebt.sub(totalAssetsAfterClaim); } // We cannot incur in additional losses during liquidatePosition because they // have already been accounted for in the check above, so we ignore them uint256 _amountFreed; (_amountFreed, ) = liquidatePosition(_debtOutstanding.add(_profit)); _debtPayment = Math.min(_debtOutstanding, _amountFreed); } function adjustPosition(uint256 _debtOutstanding) internal override { //Functions that should only be used during the Tend() call //Sell all available eth. if(totalETHBalance() > 0) { claimAndSellEth(); } if(DAI.balanceOf(address(this)) > 0) { //Try and swap DAI back to LUSD. Only use Curve so we can get an expected amount out to compare before swapping //This function should NOT fail even if we can't get enough LUSD at the moment to assure the ETH -> DAI swap still goes through _tryToSellDAIForLUSDonCurve(); } // Provide any leftover balance to the stability pool // Use zero address for frontend as we are interacting with the contracts directly uint256 wantBalance = balanceOfWant(); if (wantBalance > _debtOutstanding) { stabilityPool.provideToSP( wantBalance.sub(_debtOutstanding), address(0) ); } } function liquidatePosition(uint256 _amountNeeded) internal override returns (uint256 _liquidatedAmount, uint256 _loss) { uint256 balance = balanceOfWant(); // Check if we can handle it without withdrawing from stability pool if (balance >= _amountNeeded) { return (_amountNeeded, 0); } // Only need to free the amount of want not readily available uint256 amountToWithdraw = _amountNeeded.sub(balance); uint256 stabilityBalance = stabilityPool.getCompoundedLUSDDeposit(address(this)); if(amountToWithdraw > stabilityBalance) { //This will cause withdraws to fail if is for more than our LUSD balance while we still have DAI in the strat //This way we do not report incorrect losses before DAI can be swapped back to LUSD require(DAI.balanceOf(address(this)) == 0, "To much DAI"); stabilityPool.withdrawFromSP(stabilityBalance); } else { stabilityPool.withdrawFromSP(amountToWithdraw); } // After withdrawing from the stability pool it could happen that we have // enough LQTY / ETH to cover a loss before reporting it. // However, doing a swap at this point could make withdrawals insecure // and front-runnable, so we assume LUSD that cannot be returned is a // realized loss. uint256 looseWant = balanceOfWant(); if (_amountNeeded > looseWant) { _liquidatedAmount = looseWant; _loss = _amountNeeded.sub(looseWant); } else { _liquidatedAmount = _amountNeeded; _loss = 0; } } function liquidateAllPositions() internal override returns (uint256 _amountFreed) { stabilityPool.withdrawFromSP( stabilityPool.getCompoundedLUSDDeposit(address(this)) ); //Swap any DAI back to LUSD //May need to adjust slippage allowed before this depending on peg uint256 daiBalance = DAI.balanceOf(address(this)); if (daiBalance > 0) { _sellDAIAmountForLusd(daiBalance); } return balanceOfWant(); } function prepareMigration(address _newStrategy) internal override { if (stabilityPool.getCompoundedLUSDDeposit(address(this)) <= 0) { return; } // Withdraw entire LUSD balance from Stability Pool // ETH + LQTY + DAI gains should be harvested before migrating // `migrate` will automatically forward all `want` in this strategy to the new one stabilityPool.withdrawFromSP( stabilityPool.getCompoundedLUSDDeposit(address(this)) ); } function protectedTokens() internal view override returns (address[] memory) {} function ethToWant(uint256 _amtInWei) public view virtual override returns (uint256) { return _amtInWei.mul(priceFeed.lastGoodPrice()).div(1e18); } // ----------------- PUBLIC BALANCES ----------------- function balanceOfWant() public view returns (uint256) { return want.balanceOf(address(this)); } function totalLUSDBalance() public view returns (uint256) { return balanceOfWant().add( stabilityPool.getCompoundedLUSDDeposit(address(this)) ); } function totalLQTYBalance() public view returns (uint256) { return LQTY.balanceOf(address(this)).add( stabilityPool.getDepositorLQTYGain(address(this)) ); } function totalETHBalance() public view returns (uint256) { return address(this).balance.add( stabilityPool.getDepositorETHGain(address(this)) ); } // ----------------- SUPPORT FUNCTIONS ---------- function _checkAllowance( address _contract, IERC20 _token, uint256 _amount ) internal { if (_token.allowance(address(this), _contract) < _amount) { _token.safeApprove(_contract, 0); _token.safeApprove(_contract, type(uint256).max); } } function _claimRewards() internal { // Withdraw minimum amount to force LQTY and ETH to be claimed if (stabilityPool.getCompoundedLUSDDeposit(address(this)) > 0) { stabilityPool.withdrawFromSP(0); } // Convert LQTY rewards to DAI if (LQTY.balanceOf(address(this)) > 0) { _sellLQTYforDAI(); } // Convert ETH obtained from liquidations to DAI uint256 ethBalance = address(this).balance; if (ethBalance > 0) { _sellETHforDAI(ethBalance); } // Convert all outstanding DAI back to LUSD uint256 daiBalance = DAI.balanceOf(address(this)); if (daiBalance > 0) { _sellDAIAmountForLusd(daiBalance); } } // ----------------- TOKEN CONVERSIONS ----------------- function _sellLQTYforDAI() internal { _checkAllowance(address(router), LQTY, LQTY.balanceOf(address(this))); bytes memory path = abi.encodePacked( address(LQTY), // LQTY-ETH lqtyToEthFee, address(WETH), // ETH-DAI ethToDaiFee, address(DAI) ); // Proceeds from LQTY are not subject to minExpectedSwapPercentage // so they could get sandwiched if we end up in an uncle block router.exactInput( ISwapRouter.ExactInputParams( path, address(this), now, LQTY.balanceOf(address(this)), 0 ) ); } function _sellETHforDAI(uint256 ethBalance) internal { uint256 ethUSD = priceFeed.fetchPrice(); // Balance * Price * Swap Percentage (adjusted to 18 decimals) uint256 minExpected = ethBalance .mul(ethUSD) .mul(minExpectedSwapPercentage) .div(MAX_BPS) .div(1e18); ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams( address(WETH), // tokenIn address(DAI), // tokenOut ethToDaiFee, // ETH-DAI fee address(this), // recipient now, // deadline ethBalance, // amountIn minExpected, // amountOut 0 // sqrtPriceLimitX96 ); router.exactInputSingle{value: ethBalance}(params); router.refundETH(); } function _sellDAIAmountForLusd(uint256 _amount) internal { require(DAI.balanceOf(address(this)) >= _amount, "Not enough DAI"); if (convertDAItoLUSDonCurve) { _sellDAIAmountForLUSDonCurve(_amount); } else { _sellDAIAmountForLUSDonUniswap(_amount); } } function _sellDAIAmountForLUSDonCurve(uint256 daiBalance) internal { _checkAllowance(address(curvePool), DAI, daiBalance); curvePool.exchange_underlying( 1, // from DAI index 0, // to LUSD index daiBalance, // amount daiBalance.mul(minExpectedSwapPercentage).div(MAX_BPS) // minDy ); } function _sellDAIAmountForLUSDonUniswap(uint256 daiBalance) internal { _checkAllowance(address(router), DAI, daiBalance); ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams( address(DAI), // tokenIn address(want), // tokenOut daiToLusdFee, // DAI-LUSD fee address(this), // recipient now, // deadline daiBalance, // amountIn daiBalance.mul(minExpectedSwapPercentage).div(MAX_BPS), // amountOut 0 // sqrtPriceLimitX96 ); router.exactInputSingle(params); } //Function only called during tend() and it will not send the tx unless we believe it will go through //This allows us to only sell the DAI if we know it can get enough out without the whole tx failing based on our slippage tollerance //Meaning we can still succefully claim and sell ETH -> DAI even if we currently cant go from DAI -> LUSD function _tryToSellDAIForLUSDonCurve() internal { uint256 _amount = DAI.balanceOf(address(this)); uint256 minOut = _amount.mul(minExpectedSwapPercentage).div(MAX_BPS); uint256 actualOut = curvePool.get_dy_underlying(1, 0, _amount); if(actualOut >= minOut) { _checkAllowance(address(curvePool), DAI, _amount); curvePool.exchange_underlying( 1, // from DAI index 0, // to LUSD index _amount, // amount minOut // minDy ); } } //To be called during tend() if needed //If we have an extreme amount of ETH maxEthtoSell can be updated before this call function claimAndSellEth() internal { if (stabilityPool.getCompoundedLUSDDeposit(address(this)) > 0) { stabilityPool.withdrawFromSP(0); } uint256 ethBalance = Math.min(address(this).balance, maxEthToSell); //check to make sure we actually claimed eth if(ethBalance == 0) return; _sellETHforDAI(ethBalance); } //To be called if we need to swap less than the full amount of DAI to LUSD due to the peg or current liquidity function sellDaiAmountToLusd(uint256 _amount) external onlyEmergencyAuthorized { _sellDAIAmountForLusd(_amount); } function tendTrigger(uint256 callCostInWei) public view override returns (bool){ uint256 totalAssets = estimatedTotalAssets(); uint256 ethBalance = totalETHBalance(); if(ethBalance == 0) return false; if(getBaseFee() > maxTendBaseFee) return false; if(ethBalance >= maxEthAmount) return true; // check if the gas cost is higher than 10% of ethBalance. if it is, block tend. if (callCostInWei > ethBalance / 10) return false; uint256 ethInWant = ethToWant(ethBalance); uint256 maxAllowedEth = totalAssets.mul(maxEthPercent).div(MAX_BPS); if(ethInWant > maxAllowedEth) return true; return false; } //This expects TendTrigger is keeping up with ETH accumulation function harvestTrigger(uint256 callCostInWei) public view override returns (bool) { // Should not trigger if strategy is not active (no assets and no debtRatio). This means we don't need to adjust keeper job. if (!isActive()) { return false; } StrategyParams memory params = vault.strategies(address(this)); uint256 assets = estimatedTotalAssets(); uint256 debt = params.totalDebt; //Determines if we would likely be able to swap the current non LUSD balance from DAI -> LUSD. Should not harvest if not //Make sure the amount to swap is above 1 to avaid errors with curve call uint256 needToSwap = assets.sub(totalLUSDBalance()); if(needToSwap > 0) { if(curvePool.get_dy_underlying(1, 0, needToSwap) < needToSwap.mul(minExpectedSwapPercentage).div(MAX_BPS)) { return false; } } // check if the base fee gas price is higher than we allow. if it is, block harvests. if (!isBaseFeeAcceptable()) { return false; } // harvest if we have a profit to claim at our upper limit without considering gas price uint256 claimableProfit = assets > debt ? assets.sub(debt) : 0; // harvest if we have a sufficient profit to claim, but only if our gas price is acceptable if (claimableProfit > harvestProfitMin) { return true; } // Should not trigger if we haven't waited long enough since previous harvest if (block.timestamp.sub(params.lastReport) < minReportDelay) return false; // harvest no matter what once we reach our maxDelay if (block.timestamp.sub(params.lastReport) > maxReportDelay) { return true; } // otherwise, we don't harvest return false; } // check if the current baseFee is below our external target function isBaseFeeAcceptable() internal view returns (bool) { return IBaseFee(0xb5e1CAcB567d98faaDB60a1fD4820720141f064F) .isCurrentBaseFeeAcceptable(); } function getBaseFee() internal view returns (uint256) { uint256 baseFee; try IBaseFeeOracle(0xf8d0Ec04e94296773cE20eFbeeA82e76220cD549) .basefee_global() returns (uint256 currentBaseFee) { baseFee = currentBaseFee; } catch { // Useful for testing until ganache supports london fork // Hard-code current base fee to 1000 gwei // This should also help keepers that run in a fork without // baseFee() to avoid reverting and potentially abandoning the job baseFee = 1000 gwei; } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[],"name":"EmergencyExitEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"profit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loss","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtPayment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtOutstanding","type":"uint256"}],"name":"Harvested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"debtThreshold","type":"uint256"}],"name":"UpdatedDebtThreshold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newKeeper","type":"address"}],"name":"UpdatedKeeper","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"UpdatedMaxReportDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"metadataURI","type":"string"}],"name":"UpdatedMetadataURI","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"UpdatedMinReportDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"profitFactor","type":"uint256"}],"name":"UpdatedProfitFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"rewards","type":"address"}],"name":"UpdatedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newStrategist","type":"address"}],"name":"UpdatedStrategist","type":"event"},{"inputs":[],"name":"apiVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"balanceOfWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"convertDAItoLUSDonCurve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"daiToLusdFee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"debtThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegatedAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositLUSD","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"doHealthCheck","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyExit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"estimatedTotalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ethToDaiFee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amtInWei","type":"uint256"}],"name":"ethToWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"harvestProfitMin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"callCostInWei","type":"uint256"}],"name":"harvestTrigger","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"healthCheck","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lqtyToEthFee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxEthAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxEthPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxEthToSell","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxReportDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTendBaseFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newStrategy","type":"address"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minExpectedSwapPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minReportDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"profitFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewards","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"sellDaiAmountToLusd","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_convertDAItoLUSDonCurve","type":"bool"}],"name":"setConvertDAItoLUSDonCurve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_debtThreshold","type":"uint256"}],"name":"setDebtThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_doHealthCheck","type":"bool"}],"name":"setDoHealthCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setEmergencyExit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_harvestProfitMin","type":"uint256"}],"name":"setHarvestTriggerMin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_healthCheck","type":"address"}],"name":"setHealthCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"}],"name":"setKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_delay","type":"uint256"}],"name":"setMaxReportDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_metadataURI","type":"string"}],"name":"setMetadataURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minExpectedSwapPercentage","type":"uint256"}],"name":"setMinExpectedSwapPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_delay","type":"uint256"}],"name":"setMinReportDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_profitFactor","type":"uint256"}],"name":"setProfitFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewards","type":"address"}],"name":"setRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategist","type":"address"}],"name":"setStrategist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"_lqtyToEthFee","type":"uint24"},{"internalType":"uint24","name":"_ethToDaiFee","type":"uint24"},{"internalType":"uint24","name":"_daiToLusdFee","type":"uint24"}],"name":"setSwapFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxEthPercent","type":"uint256"},{"internalType":"uint256","name":"_maxEthAmount","type":"uint256"},{"internalType":"uint256","name":"_maxEthToSell","type":"uint256"},{"internalType":"uint256","name":"_maxTendBaseFee","type":"uint256"}],"name":"setTendAmounts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strategist","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swallowETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"callCostInWei","type":"uint256"}],"name":"tendTrigger","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalETHBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLQTYBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLUSDBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract VaultAPI","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"want","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountNeeded","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"_loss","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawLUSD","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrapETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040523480156200001157600080fd5b5060405162006349380380620063498339810160408190526200003491620005a0565b806200004381338080620000ed565b5050600b805460018054610100600160a81b03191674ddcea799ff1699e98edf118e0629a974df7df0120017905561010061ff00199091161764ffffff00001916630bb800001762ffffff60281b1916660bb800000000001762ffffff60401b19166901f40000000000000000179055612648600c55683635c9adc5dea00000600d55642e90edd000600e556064600f5568056bc75e2d63100000601055600019601155620007d9565b6006546001600160a01b031615620001225760405162461bcd60e51b8152600401620001199062000691565b60405180910390fd5b600280546001600160a01b0319166001600160a01b03868116919091179182905560408051637e062a3560e11b81529051929091169163fc0c546a91600480820192602092909190829003018186803b1580156200017f57600080fd5b505afa15801562000194573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ba9190620005a0565b600680546001600160a01b0319166001600160a01b039283161790819055620001f4911685600019620002d1602090811b620037ae17901c565b600380546001600160a01b038086166001600160a01b03199283161790925560048054858416908316178082556005805486861694169390931790925560006007819055620151806008556064600955600a5560025460405163095ea7b360e01b81529084169363095ea7b3936200027493911691600019910162000643565b602060405180830381600087803b1580156200028f57600080fd5b505af1158015620002a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ca9190620005d0565b5050505050565b801580620003605750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e906200030a903090869060040162000629565b60206040518083038186803b1580156200032357600080fd5b505afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e9190620005f2565b155b6200037f5760405162461bcd60e51b8152600401620001199062000749565b620003da8363095ea7b360e01b8484604051602401620003a192919062000643565b60408051808303601f190181529190526020810180516001600160e01b0319939093166001600160e01b0393841617905290620003df16565b505050565b60606200043b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200047b60201b620038ad179092919060201c565b805190915015620003da57808060200190518101906200045c9190620005d0565b620003da5760405162461bcd60e51b81526004016200011990620006ff565b60606200048c848460008562000494565b949350505050565b6060620004a18562000566565b620004c05760405162461bcd60e51b81526004016200011990620006c8565b60006060866001600160a01b03168587604051620004df91906200060b565b60006040518083038185875af1925050503d80600081146200051e576040519150601f19603f3d011682016040523d82523d6000602084013e62000523565b606091505b50915091508115620005395791506200048c9050565b8051156200054a5780518082602001fd5b8360405162461bcd60e51b81526004016200011991906200065c565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906200048c575050151592915050565b600060208284031215620005b2578081fd5b81516001600160a01b0381168114620005c9578182fd5b9392505050565b600060208284031215620005e2578081fd5b81518015158114620005c9578182fd5b60006020828403121562000604578081fd5b5051919050565b600082516200061f818460208701620007a6565b9190910192915050565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b60006020825282518060208401526200067d816040850160208701620007a6565b601f01601f19169190910160400192915050565b6020808252601c908201527f537472617465677920616c726561647920696e697469616c697a656400000000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000606082015260800190565b60005b83811015620007c3578181015183820152602001620007a9565b83811115620007d3576000848401525b50505050565b615b6080620007e96000396000f3fe6080604052600436106103a65760003560e01c8063748747e6116101e7578063ad09c2281161010d578063ec38a862116100a0578063f4eac0091161006f578063f4eac009146109b3578063fbfa77cf146109c8578063fcf2d0ad146109dd578063fef2acae146109f2576103ad565b8063ec38a8621461093e578063ed882c2b1461095e578063efbb5cb01461097e578063f017c92f14610993576103ad565b8063c7b9d530116100dc578063c7b9d530146108c9578063ce5494bb146108e9578063dd15c95e14610909578063eb4dc30414610929576103ad565b8063ad09c2281461086a578063b252720b1461088a578063b912e1ca1461089f578063c1a3d44c146108b4576103ad565b80638e6350e211610185578063a752c3ca11610154578063a752c3ca1461080b578063a85ef67814610820578063ac00ff2614610835578063aced166114610855576103ad565b80638e6350e2146107ac57806391397ab4146107c157806395e80c50146107e15780639ec5a894146107f6576103ad565b80637fb6085f116101c15780637fb6085f14610758578063802a59161461076d57806380d0e030146107825780638cdfe16614610797576103ad565b8063748747e6146106f8578063750521f514610718578063780022a014610738576103ad565b806328b7ccf7116102cc578063545ae8541161026a5780635fbeb25f116102395780635fbeb25f14610699578063650d1880146106ae5780636718835f146106ce578063695ec8da146106e3576103ad565b8063545ae8541461063a5780635641ec031461064f5780635ac90945146106645780635eff5b1014610679576103ad565b806336515795116102a657806336515795146105db57806339a172a8146105f0578063440368a3146106105780634641257d14610625576103ad565b806328b7ccf71461058657806329c480551461059b5780632e1a7d4d146105bb576103ad565b80630f969b87116103445780631f1fcd51116103135780631f1fcd51146105185780631fe4a6861461053a57806322f3e2d41461054f5780632582941014610571576103ad565b80630f969b871461049457806311bc8245146104b457806319e3437a146104d45780631d12f28b146104f6576103ad565b806306fdde031161038057806306fdde031461041f5780630b294723146104345780630b643781146104545780630d45d9be14610474576103ad565b806301681a62146103b257806303ee438c146103d4578063068196d4146103ff576103ad565b366103ad57005b600080fd5b3480156103be57600080fd5b506103d26103cd3660046152e1565b610a07565b005b3480156103e057600080fd5b506103e9610ba6565b6040516103f6919061564a565b60405180910390f35b34801561040b57600080fd5b506103d261041a3660046154b1565b610c34565b34801561042b57600080fd5b506103e9610e19565b34801561044057600080fd5b506103d261044f366004615481565b610e50565b34801561046057600080fd5b506103d261046f366004615481565b611045565b34801561048057600080fd5b506103d261048f366004615481565b611208565b3480156104a057600080fd5b506103d26104af366004615481565b61139c565b3480156104c057600080fd5b506103d26104cf3660046152e1565b611429565b3480156104e057600080fd5b506104e961152a565b6040516103f691906159f9565b34801561050257600080fd5b5061050b61153c565b6040516103f691906155d1565b34801561052457600080fd5b5061052d611542565b6040516103f6919061557f565b34801561054657600080fd5b5061052d611551565b34801561055b57600080fd5b50610564611560565b6040516103f691906155c6565b34801561057d57600080fd5b506103e9611602565b34801561059257600080fd5b5061050b611621565b3480156105a757600080fd5b506103d26105b6366004615481565b611627565b3480156105c757600080fd5b5061050b6105d6366004615481565b6117c2565b3480156105e757600080fd5b5061050b61181d565b3480156105fc57600080fd5b506103d261060b366004615481565b611823565b34801561061c57600080fd5b506103d26118a5565b34801561063157600080fd5b506103d2611ace565b34801561064657600080fd5b506103d2611fa7565b34801561065b57600080fd5b50610564612048565b34801561067057600080fd5b5061050b612051565b34801561068557600080fd5b506103d2610694366004615481565b612057565b3480156106a557600080fd5b5061050b6121eb565b3480156106ba57600080fd5b506105646106c9366004615481565b6121f1565b3480156106da57600080fd5b506105646122b5565b3480156106ef57600080fd5b5061050b6122be565b34801561070457600080fd5b506103d26107133660046152e1565b6123d3565b34801561072457600080fd5b506103d2610733366004615351565b61247e565b34801561074457600080fd5b5061050b610753366004615481565b612515565b34801561076457600080fd5b5061050b6125b8565b34801561077957600080fd5b5061050b6125be565b34801561078e57600080fd5b506105646125c4565b3480156107a357600080fd5b5061050b6125d2565b3480156107b857600080fd5b5061050b6125d8565b3480156107cd57600080fd5b506103d26107dc366004615481565b6125dd565b3480156107ed57600080fd5b5061050b61265f565b34801561080257600080fd5b5061052d612665565b34801561081757600080fd5b506104e9612674565b34801561082c57600080fd5b506103d2612685565b34801561084157600080fd5b506103d2610850366004615319565b61270c565b34801561086157600080fd5b5061052d6127f8565b34801561087657600080fd5b506103d2610885366004615319565b612807565b34801561089657600080fd5b5061052d6129b0565b3480156108ab57600080fd5b506104e96129c4565b3480156108c057600080fd5b5061050b6129d6565b3480156108d557600080fd5b506103d26108e43660046152e1565b612a57565b3480156108f557600080fd5b506103d26109043660046152e1565b612b02565b34801561091557600080fd5b506103d261092436600461543c565b612c4d565b34801561093557600080fd5b5061050b612e30565b34801561094a57600080fd5b506103d26109593660046152e1565b612ebf565b34801561096a57600080fd5b50610564610979366004615481565b613052565b34801561098a57600080fd5b5061050b613284565b34801561099f57600080fd5b506103d26109ae366004615481565b613463565b3480156109bf57600080fd5b5061050b6134e5565b3480156109d457600080fd5b5061052d6134eb565b3480156109e957600080fd5b506103d26134fa565b3480156109fe57600080fd5b5061050b61371f565b610a0f6138c4565b6001600160a01b0316336001600160a01b031614610a485760405162461bcd60e51b8152600401610a3f90615827565b60405180910390fd5b6006546001600160a01b0382811691161415610a765760405162461bcd60e51b8152600401610a3f90615682565b6002546001600160a01b0382811691161415610aa45760405162461bcd60e51b8152600401610a3f906157a8565b6060610aae613941565b905060005b8151811015610b0957818181518110610ac857fe5b60200260200101516001600160a01b0316836001600160a01b03161415610b015760405162461bcd60e51b8152600401610a3f906158be565b600101610ab3565b50610ba2610b156138c4565b6040516370a0823160e01b81526001600160a01b038516906370a0823190610b4190309060040161557f565b60206040518083038186803b158015610b5957600080fd5b505afa158015610b6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b919190615499565b6001600160a01b0385169190613946565b5050565b6000805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610c2c5780601f10610c0157610100808354040283529160200191610c2c565b820191906000526020600020905b815481529060010190602001808311610c0f57829003601f168201915b505050505081565b6003546001600160a01b0316331480610c655750610c506138c4565b6001600160a01b0316336001600160a01b0316145b80610d065750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015610cb957600080fd5b505afa158015610ccd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf191906152fd565b6001600160a01b0316336001600160a01b0316145b80610da75750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610d5a57600080fd5b505afa158015610d6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9291906152fd565b6001600160a01b0316336001600160a01b0316145b610dc35760405162461bcd60e51b8152600401610a3f90615827565b612710841115610de55760405162461bcd60e51b8152600401610a3f90615800565b60008211610e055760405162461bcd60e51b8152600401610a3f90615723565b600f93909355601091909155601155600e55565b6040805180820190915260208082527f53747261746567794c69717569747953746162696c697479506f6f6c4c5553449082015290565b6003546001600160a01b0316331480610e815750610e6c6138c4565b6001600160a01b0316336001600160a01b0316145b80610f225750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015610ed557600080fd5b505afa158015610ee9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0d91906152fd565b6001600160a01b0316336001600160a01b0316145b80610fc35750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610f7657600080fd5b505afa158015610f8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fae91906152fd565b6001600160a01b0316336001600160a01b0316145b610fdf5760405162461bcd60e51b8152600401610a3f90615827565b604051632e54bf9560e01b8152600080516020615aeb83398151915290632e54bf95906110109084906004016155d1565b600060405180830381600087803b15801561102a57600080fd5b505af115801561103e573d6000803e3d6000fd5b5050505050565b6003546001600160a01b031633148061107657506110616138c4565b6001600160a01b0316336001600160a01b0316145b806111175750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b1580156110ca57600080fd5b505afa1580156110de573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110291906152fd565b6001600160a01b0316336001600160a01b0316145b806111b85750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561116b57600080fd5b505afa15801561117f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a391906152fd565b6001600160a01b0316336001600160a01b0316145b6111d45760405162461bcd60e51b8152600401610a3f90615827565b604051635f788d6560e01b8152600080516020615aeb83398151915290635f788d6590611010908490600090600401615a09565b6003546001600160a01b031633148061123957506112246138c4565b6001600160a01b0316336001600160a01b0316145b806112da5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561128d57600080fd5b505afa1580156112a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c591906152fd565b6001600160a01b0316336001600160a01b0316145b8061137b5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561132e57600080fd5b505afa158015611342573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136691906152fd565b6001600160a01b0316336001600160a01b0316145b6113975760405162461bcd60e51b8152600401610a3f90615827565b600d55565b6003546001600160a01b03163314806113cd57506113b86138c4565b6001600160a01b0316336001600160a01b0316145b6113e95760405162461bcd60e51b8152600401610a3f90615827565b600a8190556040517fa68ba126373d04c004c5748c300c9fca12bd444b3d4332e261f3bd2bac4a86009061141e9083906155d1565b60405180910390a150565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561147757600080fd5b505afa15801561148b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114af91906152fd565b6001600160a01b0316336001600160a01b031614806114e657506114d16138c4565b6001600160a01b0316336001600160a01b0316145b6115025760405162461bcd60e51b8152600401610a3f90615827565b600180546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b600b54600160281b900462ffffff1681565b600a5481565b6006546001600160a01b031681565b6003546001600160a01b031681565b6002546040516339ebf82360e01b815260009182916001600160a01b03909116906339ebf8239061159590309060040161557f565b6101206040518083038186803b1580156115ae57600080fd5b505afa1580156115c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e691906153be565b6040015111806115fd575060006115fb613284565b115b905090565b604080518082019091526005815264302e342e3360d81b602082015290565b60085481565b6003546001600160a01b031633148061165857506116436138c4565b6001600160a01b0316336001600160a01b0316145b806116f95750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b1580156116ac57600080fd5b505afa1580156116c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e491906152fd565b6001600160a01b0316336001600160a01b0316145b8061179a5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561174d57600080fd5b505afa158015611761573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061178591906152fd565b6001600160a01b0316336001600160a01b0316145b6117b65760405162461bcd60e51b8152600401610a3f90615827565b6117bf81613965565b50565b6002546000906001600160a01b031633146117ef5760405162461bcd60e51b8152600401610a3f90615788565b60006117fa83613a2d565b600654909350909150611817906001600160a01b03163383613946565b50919050565b600f5481565b6003546001600160a01b0316331480611854575061183f6138c4565b6001600160a01b0316336001600160a01b0316145b6118705760405162461bcd60e51b8152600401610a3f90615827565b60078190556040517fbb2c369a0355a34b02ab5fce0643150c87e1c8dfe7c918d465591879f57948b19061141e9083906155d1565b6005546001600160a01b03163314806118c857506003546001600160a01b031633145b806118eb57506118d66138c4565b6001600160a01b0316336001600160a01b0316145b8061198c5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561193f57600080fd5b505afa158015611953573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197791906152fd565b6001600160a01b0316336001600160a01b0316145b80611a2d5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b1580156119e057600080fd5b505afa1580156119f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1891906152fd565b6001600160a01b0316336001600160a01b0316145b611a495760405162461bcd60e51b8152600401610a3f90615827565b6002546040805163bf3759b560e01b81529051611acc926001600160a01b03169163bf3759b5916004808301926020929190829003018186803b158015611a8f57600080fd5b505afa158015611aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac79190615499565b613c90565b565b6005546001600160a01b0316331480611af157506003546001600160a01b031633145b80611b145750611aff6138c4565b6001600160a01b0316336001600160a01b0316145b80611bb55750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015611b6857600080fd5b505afa158015611b7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba091906152fd565b6001600160a01b0316336001600160a01b0316145b80611c565750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015611c0957600080fd5b505afa158015611c1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4191906152fd565b6001600160a01b0316336001600160a01b0316145b611c725760405162461bcd60e51b8152600401610a3f90615827565b6000806000600260009054906101000a90046001600160a01b03166001600160a01b031663bf3759b56040518163ffffffff1660e01b815260040160206040518083038186803b158015611cc557600080fd5b505afa158015611cd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cfd9190615499565b600b5490915060009060ff1615611d5a576000611d18613dc1565b905082811015611d3357611d2c8382613f3d565b9350611d48565b82811115611d4857611d458184613f3d565b94505b611d528385613f3d565b915050611d6b565b611d6382613f86565b919550935090505b6002546040516339ebf82360e01b81526000916001600160a01b0316906339ebf82390611d9c90309060040161557f565b6101206040518083038186803b158015611db557600080fd5b505afa158015611dc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ded91906153be565b60c001516002546040516328766ebf60e21b81529192506001600160a01b03169063a1d9bafc90611e2690889088908790600401615a20565b602060405180830381600087803b158015611e4057600080fd5b505af1158015611e54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e789190615499565b9250611e8383613c90565b60015460ff168015611ea4575060015461010090046001600160a01b031615155b15611f565760015460405163c70fa00b60e01b81526101009091046001600160a01b03169063c70fa00b90611ee59088908890879089908890600401615a51565b60206040518083038186803b158015611efd57600080fd5b505afa158015611f11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f359190615335565b611f515760405162461bcd60e51b8152600401610a3f906156fd565b611f63565b6001805460ff1916811790555b7f4c0f499ffe6befa0ca7c826b0916cf87bea98de658013e76938489368d60d50985858486604051611f989493929190615a36565b60405180910390a15050505050565b611faf6138c4565b6001600160a01b0316336001600160a01b031614611fdf5760405162461bcd60e51b8152600401610a3f90615827565b6000336001600160a01b031647604051611ff89061557c565b60006040518083038185875af1925050503d8060008114612035576040519150601f19603f3d011682016040523d82523d6000602084013e61203a565b606091505b50509050806117bf57600080fd5b600b5460ff1681565b600e5481565b6003546001600160a01b031633148061208857506120736138c4565b6001600160a01b0316336001600160a01b0316145b806121295750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b1580156120dc57600080fd5b505afa1580156120f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211491906152fd565b6001600160a01b0316336001600160a01b0316145b806121ca5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561217d57600080fd5b505afa158015612191573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b591906152fd565b6001600160a01b0316336001600160a01b0316145b6121e65760405162461bcd60e51b8152600401610a3f90615827565b600c55565b600d5481565b6000806121fc613284565b9050600061220861371f565b90508061221a576000925050506122b0565b600e54612225614084565b1115612236576000925050506122b0565b601054811061224a576001925050506122b0565b600a8104841115612260576000925050506122b0565b600061226b82612515565b9050600061229061271061228a600f548761411b90919063ffffffff16565b90614155565b9050808211156122a75760019450505050506122b0565b60009450505050505b919050565b60015460ff1681565b60405163f5f1595d60e01b81526000906115fd90600080516020615aeb8339815191529063f5f1595d906122f690309060040161557f565b60206040518083038186803b15801561230e57600080fd5b505afa158015612322573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123469190615499565b6040516370a0823160e01b8152736dea81c8171d0ba574754ef6f8b412f2ed88c54d906370a082319061237d90309060040161557f565b60206040518083038186803b15801561239557600080fd5b505afa1580156123a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123cd9190615499565b90614197565b6003546001600160a01b031633148061240457506123ef6138c4565b6001600160a01b0316336001600160a01b0316145b6124205760405162461bcd60e51b8152600401610a3f90615827565b6001600160a01b03811661243357600080fd5b600580546001600160a01b0319166001600160a01b0383161790556040517f2f202ddb4a2e345f6323ed90f8fc8559d770a7abbbeee84dde8aca3351fe71549061141e90839061557f565b6003546001600160a01b03163314806124af575061249a6138c4565b6001600160a01b0316336001600160a01b0316145b6124cb5760405162461bcd60e51b8152600401610a3f90615827565b6124d7600083836151af565b507f300e67d5a415b6d015a471d9c7b95dd58f3e8290af965e84e0f845de2996dda6828260405161250992919061561b565b60405180910390a15050565b60006125b2670de0b6b3a764000061228a734c517d4e2c851ca76d7ec94b805269df0f2201de6001600160a01b0316630490be836040518163ffffffff1660e01b815260040160206040518083038186803b15801561257357600080fd5b505afa158015612587573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ab9190615499565b859061411b565b92915050565b60105481565b600c5481565b600b54610100900460ff1681565b60095481565b600090565b6003546001600160a01b031633148061260e57506125f96138c4565b6001600160a01b0316336001600160a01b0316145b61262a5760405162461bcd60e51b8152600401610a3f90615827565b60098190556040517fd94596337df4c2f0f44d30a7fc5db1c7bb60d9aca4185ed77c6fd96eb45ec2989061141e9083906155d1565b60075481565b6004546001600160a01b031681565b600b5462010000900462ffffff1681565b61268d6138c4565b6001600160a01b0316336001600160a01b0316146126bd5760405162461bcd60e51b8152600401610a3f90615827565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b15801561102a57600080fd5b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561275a57600080fd5b505afa15801561276e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279291906152fd565b6001600160a01b0316336001600160a01b031614806127c957506127b46138c4565b6001600160a01b0316336001600160a01b0316145b6127e55760405162461bcd60e51b8152600401610a3f90615827565b6001805460ff1916911515919091179055565b6005546001600160a01b031681565b6003546001600160a01b031633148061283857506128236138c4565b6001600160a01b0316336001600160a01b0316145b806128d95750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561288c57600080fd5b505afa1580156128a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c491906152fd565b6001600160a01b0316336001600160a01b0316145b8061297a5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561292d57600080fd5b505afa158015612941573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296591906152fd565b6001600160a01b0316336001600160a01b0316145b6129965760405162461bcd60e51b8152600401610a3f90615827565b600b80549115156101000261ff0019909216919091179055565b60015461010090046001600160a01b031681565b600b54600160401b900462ffffff1681565b6006546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612a0790309060040161557f565b60206040518083038186803b158015612a1f57600080fd5b505afa158015612a33573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115fd9190615499565b6003546001600160a01b0316331480612a885750612a736138c4565b6001600160a01b0316336001600160a01b0316145b612aa45760405162461bcd60e51b8152600401610a3f90615827565b6001600160a01b038116612ab757600080fd5b600380546001600160a01b0319166001600160a01b0383161790556040517f352ececae6d7d1e6d26bcf2c549dfd55be1637e9b22dc0cf3b71ddb36097a6b49061141e90839061557f565b6002546001600160a01b03163314612b1957600080fd5b6002546040805163fbfa77cf60e01b815290516001600160a01b039283169284169163fbfa77cf916004808301926020929190829003018186803b158015612b6057600080fd5b505afa158015612b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b9891906152fd565b6001600160a01b031614612bab57600080fd5b612bb4816141bc565b6006546040516370a0823160e01b81526117bf9183916001600160a01b03909116906370a0823190612bea90309060040161557f565b60206040518083038186803b158015612c0257600080fd5b505afa158015612c16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c3a9190615499565b6006546001600160a01b03169190613946565b6003546001600160a01b0316331480612c7e5750612c696138c4565b6001600160a01b0316336001600160a01b0316145b80612d1f5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015612cd257600080fd5b505afa158015612ce6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0a91906152fd565b6001600160a01b0316336001600160a01b0316145b80612dc05750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015612d7357600080fd5b505afa158015612d87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dab91906152fd565b6001600160a01b0316336001600160a01b0316145b612ddc5760405162461bcd60e51b8152600401610a3f90615827565b600b805464ffffff000019166201000062ffffff958616021767ffffff00000000001916600160281b93851693909302929092176affffff00000000000000001916600160401b9190931602919091179055565b604051621cdc4760e81b81526000906115fd90600080516020615aeb83398151915290631cdc470090612e6790309060040161557f565b60206040518083038186803b158015612e7f57600080fd5b505afa158015612e93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eb79190615499565b6123cd6129d6565b6003546001600160a01b03163314612ee95760405162461bcd60e51b8152600401610a3f9061565d565b6001600160a01b038116612efc57600080fd5b6002546004805460405163095ea7b360e01b81526001600160a01b039384169363095ea7b393612f339390911691600091016155ad565b602060405180830381600087803b158015612f4d57600080fd5b505af1158015612f61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f859190615335565b50600480546001600160a01b0319166001600160a01b038381169190911780835560025460405163095ea7b360e01b81529083169363095ea7b393612fd093169160001991016155ad565b602060405180830381600087803b158015612fea57600080fd5b505af1158015612ffe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130229190615335565b507fafbb66abf8f3b719799940473a4052a3717cdd8e40fb6c8a3faadab316b1a0698160405161141e919061557f565b600061305c611560565b613068575060006122b0565b613070615229565b6002546040516339ebf82360e01b81526001600160a01b03909116906339ebf823906130a090309060040161557f565b6101206040518083038186803b1580156130b957600080fd5b505afa1580156130cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130f191906153be565b905060006130fd613284565b60c08301519091506000613119613112612e30565b8490613f3d565b905080156131dc5761313c61271061228a600c548461411b90919063ffffffff16565b6040516307211ef760e01b815273ed279fdd11ca84beef15af5d39bb4d4bee23f0ca906307211ef7906131799060019060009087906004016155da565b60206040518083038186803b15801561319157600080fd5b505afa1580156131a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131c99190615499565b10156131dc5760009450505050506122b0565b6131e46142ed565b6131f55760009450505050506122b0565b600082841161320557600061320f565b61320f8484613f3d565b9050600d54811115613229576001955050505050506122b0565b60075460a086015161323c904290613f3d565b1015613250576000955050505050506122b0565b60085460a0860151613263904290613f3d565b1115613277576001955050505050506122b0565b5060009695505050505050565b6040516370a0823160e01b81526000908190600080516020615b0b833981519152906370a08231906132ba90309060040161557f565b60206040518083038186803b1580156132d257600080fd5b505afa1580156132e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061330a9190615499565b9050600080821161331c5760006133a9565b6040516307211ef760e01b815273ed279fdd11ca84beef15af5d39bb4d4bee23f0ca906307211ef7906133599060019060009087906004016155da565b60206040518083038186803b15801561337157600080fd5b505afa158015613385573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133a99190615499565b905061345c613450670de0b6b3a764000061228a734c517d4e2c851ca76d7ec94b805269df0f2201de6001600160a01b0316630490be836040518163ffffffff1660e01b815260040160206040518083038186803b15801561340a57600080fd5b505afa15801561341e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134429190615499565b61344a61371f565b9061411b565b6123cd836123cd612e30565b9250505090565b6003546001600160a01b0316331480613494575061347f6138c4565b6001600160a01b0316336001600160a01b0316145b6134b05760405162461bcd60e51b8152600401610a3f90615827565b60088190556040517f5430e11864ad7aa9775b07d12657fe52df9aa2ba734355bd8ef8747be2c800c59061141e9083906155d1565b60115481565b6002546001600160a01b031681565b6003546001600160a01b031633148061352b57506135166138c4565b6001600160a01b0316336001600160a01b0316145b806135cc5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561357f57600080fd5b505afa158015613593573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b791906152fd565b6001600160a01b0316336001600160a01b0316145b8061366d5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561362057600080fd5b505afa158015613634573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061365891906152fd565b6001600160a01b0316336001600160a01b0316145b6136895760405162461bcd60e51b8152600401610a3f90615827565b600b805460ff191660011790556002546040805163507257cd60e11b815290516001600160a01b039092169163a0e4af9a9160048082019260009290919082900301818387803b1580156136dc57600080fd5b505af11580156136f0573d6000803e3d6000fd5b50506040517f97e963041e952738788b9d4871d854d282065b8f90a464928d6528f2e9a4fd0b925060009150a1565b60405163389e92a560e01b81526000906115fd90600080516020615aeb8339815191529063389e92a59061375790309060040161557f565b60206040518083038186803b15801561376f57600080fd5b505afa158015613783573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137a79190615499565b4790614197565b8015806138365750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e906137e49030908690600401615593565b60206040518083038186803b1580156137fc57600080fd5b505afa158015613810573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138349190615499565b155b6138525760405162461bcd60e51b8152600401610a3f906158e2565b6138a88363095ea7b360e01b84846040516024016138719291906155ad565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614374565b505050565b60606138bc8484600085614403565b949350505050565b60025460408051635aa6e67560e01b815290516000926001600160a01b031691635aa6e675916004808301926020929190829003018186803b15801561390957600080fd5b505afa15801561391d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115fd91906152fd565b606090565b6138a88363a9059cbb60e01b84846040516024016138719291906155ad565b6040516370a0823160e01b81528190600080516020615b0b833981519152906370a082319061399890309060040161557f565b60206040518083038186803b1580156139b057600080fd5b505afa1580156139c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139e89190615499565b1015613a065760405162461bcd60e51b8152600401610a3f9061584c565b600b54610100900460ff1615613a2457613a1f816144c7565b6117bf565b6117bf816145a8565b6000806000613a3a6129d6565b9050838110613a50578360009250925050613c8b565b6000613a5c8583613f3d565b604051621cdc4760e81b8152909150600090600080516020615aeb83398151915290631cdc470090613a9290309060040161557f565b60206040518083038186803b158015613aaa57600080fd5b505afa158015613abe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae29190615499565b905080821115613bf2576040516370a0823160e01b8152600080516020615b0b833981519152906370a0823190613b1d90309060040161557f565b60206040518083038186803b158015613b3557600080fd5b505afa158015613b49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b6d9190615499565b15613b8a5760405162461bcd60e51b8152600401610a3f906156d8565b604051632e54bf9560e01b8152600080516020615aeb83398151915290632e54bf9590613bbb9084906004016155d1565b600060405180830381600087803b158015613bd557600080fd5b505af1158015613be9573d6000803e3d6000fd5b50505050613c56565b604051632e54bf9560e01b8152600080516020615aeb83398151915290632e54bf9590613c239085906004016155d1565b600060405180830381600087803b158015613c3d57600080fd5b505af1158015613c51573d6000803e3d6000fd5b505050505b6000613c606129d6565b905080871115613c7e57945084613c778782613f3d565b9450613c86565b869550600094505b505050505b915091565b6000613c9a61371f565b1115613ca857613ca86146e4565b6040516370a0823160e01b8152600090600080516020615b0b833981519152906370a0823190613cdc90309060040161557f565b60206040518083038186803b158015613cf457600080fd5b505afa158015613d08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d2c9190615499565b1115613d3a57613d3a6147f6565b6000613d446129d6565b905081811115610ba257600080516020615aeb833981519152635f788d65613d6c8385613f3d565b60006040518363ffffffff1660e01b8152600401613d8b929190615a09565b600060405180830381600087803b158015613da557600080fd5b505af1158015613db9573d6000803e3d6000fd5b505050505050565b604051621cdc4760e81b8152600090600080516020615aeb83398151915290632e54bf95908290631cdc470090613dfc90309060040161557f565b60206040518083038186803b158015613e1457600080fd5b505afa158015613e28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e4c9190615499565b6040518263ffffffff1660e01b8152600401613e6891906155d1565b600060405180830381600087803b158015613e8257600080fd5b505af1158015613e96573d6000803e3d6000fd5b50506040516370a0823160e01b815260009250600080516020615b0b83398151915291506370a0823190613ece90309060040161557f565b60206040518083038186803b158015613ee657600080fd5b505afa158015613efa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f1e9190615499565b90508015613f2f57613f2f81613965565b613f376129d6565b91505090565b6000613f7f83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506149f8565b9392505050565b6002546040516339ebf82360e01b81526000918291829182916001600160a01b03909116906339ebf82390613fbf90309060040161557f565b6101206040518083038186803b158015613fd857600080fd5b505afa158015613fec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061401091906153be565b60c00151905061401e614a24565b6000614028612e30565b9050818111156140475761403c8183613f3d565b945060009350614058565b600094506140558282613f3d565b93505b600061406c6140678888614197565b613a2d565b5090506140798782614c4f565b959794965050505050565b60008073f8d0ec04e94296773ce20efbeea82e76220cd5496001600160a01b0316639436dce46040518163ffffffff1660e01b815260040160206040518083038186803b1580156140d457600080fd5b505afa925050508015614104575060408051601f3d908101601f1916820190925261410191810190615499565b60015b614114575064e8d4a51000614117565b90505b5090565b60008261412a575060006125b2565b8282028284828161413757fe5b0414613f7f5760405162461bcd60e51b8152600401610a3f90615747565b6000613f7f83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614c65565b600082820183811015613f7f5760405162461bcd60e51b8152600401610a3f906156a1565b604051621cdc4760e81b8152600090600080516020615aeb83398151915290631cdc4700906141ef90309060040161557f565b60206040518083038186803b15801561420757600080fd5b505afa15801561421b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061423f9190615499565b11614249576117bf565b604051621cdc4760e81b8152600080516020615aeb83398151915290632e54bf95908290631cdc47009061428190309060040161557f565b60206040518083038186803b15801561429957600080fd5b505afa1580156142ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142d19190615499565b6040518263ffffffff1660e01b815260040161101091906155d1565b600073b5e1cacb567d98faadb60a1fd4820720141f064f6001600160a01b03166334a9e75c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561433c57600080fd5b505afa158015614350573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115fd9190615335565b60606143c9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166138ad9092919063ffffffff16565b8051909150156138a857808060200190518101906143e79190615335565b6138a85760405162461bcd60e51b8152600401610a3f90615874565b606061440e85614c9c565b61442a5760405162461bcd60e51b8152600401610a3f906157c9565b60006060866001600160a01b031685876040516144479190615560565b60006040518083038185875af1925050503d8060008114614484576040519150601f19603f3d011682016040523d82523d6000602084013e614489565b606091505b5091509150811561449d5791506138bc9050565b8051156144ad5780518082602001fd5b8360405162461bcd60e51b8152600401610a3f919061564a565b6144f473ed279fdd11ca84beef15af5d39bb4d4bee23f0ca600080516020615b0b83398151915283614cd5565b73ed279fdd11ca84beef15af5d39bb4d4bee23f0ca6001600160a01b031663a6417ed6600160008461453761271061228a600c548961411b90919063ffffffff16565b6040518563ffffffff1660e01b815260040161455694939291906155f8565b602060405180830381600087803b15801561457057600080fd5b505af1158015614584573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba29190615499565b6145d573e592427a0aece92de3edee1f18e0157c05861564600080516020615b0b83398151915283614cd5565b6145dd615275565b6040805161010081018252600080516020615b0b83398151915281526006546001600160a01b03166020820152600b54600160401b900462ffffff169181019190915230606082015242608082015260a08101839052600c5460c082019061464e906127109061228a90879061411b565b8152600060209091015260405163414bf38960e01b815290915073e592427a0aece92de3edee1f18e0157c058615649063414bf38990614692908490600401615990565b602060405180830381600087803b1580156146ac57600080fd5b505af11580156146c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138a89190615499565b604051621cdc4760e81b8152600090600080516020615aeb83398151915290631cdc47009061471790309060040161557f565b60206040518083038186803b15801561472f57600080fd5b505afa158015614743573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147679190615499565b11156147d257604051632e54bf9560e01b8152600080516020615aeb83398151915290632e54bf959061479f906000906004016155d1565b600060405180830381600087803b1580156147b957600080fd5b505af11580156147cd573d6000803e3d6000fd5b505050505b60006147e047601154614c4f565b9050806147ed5750611acc565b6117bf81614d86565b6040516370a0823160e01b8152600090600080516020615b0b833981519152906370a082319061482a90309060040161557f565b60206040518083038186803b15801561484257600080fd5b505afa158015614856573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061487a9190615499565b9050600061489961271061228a600c548561411b90919063ffffffff16565b6040516307211ef760e01b815290915060009073ed279fdd11ca84beef15af5d39bb4d4bee23f0ca906307211ef7906148db90600190859088906004016155da565b60206040518083038186803b1580156148f357600080fd5b505afa158015614907573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061492b9190615499565b90508181106138a85761496173ed279fdd11ca84beef15af5d39bb4d4bee23f0ca600080516020615b0b83398151915285614cd5565b604051635320bf6b60e11b815273ed279fdd11ca84beef15af5d39bb4d4bee23f0ca9063a6417ed6906149a090600190600090889088906004016155f8565b602060405180830381600087803b1580156149ba57600080fd5b505af11580156149ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149f29190615499565b50505050565b60008184841115614a1c5760405162461bcd60e51b8152600401610a3f919061564a565b505050900390565b604051621cdc4760e81b8152600090600080516020615aeb83398151915290631cdc470090614a5790309060040161557f565b60206040518083038186803b158015614a6f57600080fd5b505afa158015614a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614aa79190615499565b1115614b1257604051632e54bf9560e01b8152600080516020615aeb83398151915290632e54bf9590614adf906000906004016155d1565b600060405180830381600087803b158015614af957600080fd5b505af1158015614b0d573d6000803e3d6000fd5b505050505b6040516370a0823160e01b8152600090736dea81c8171d0ba574754ef6f8b412f2ed88c54d906370a0823190614b4c90309060040161557f565b60206040518083038186803b158015614b6457600080fd5b505afa158015614b78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b9c9190615499565b1115614baa57614baa614fab565b478015614bba57614bba81614d86565b6040516370a0823160e01b8152600090600080516020615b0b833981519152906370a0823190614bee90309060040161557f565b60206040518083038186803b158015614c0657600080fd5b505afa158015614c1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c3e9190615499565b90508015610ba257610ba281613965565b6000818310614c5e5781613f7f565b5090919050565b60008183614c865760405162461bcd60e51b8152600401610a3f919061564a565b506000838581614c9257fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906138bc575050151592915050565b604051636eb1769f60e11b815281906001600160a01b0384169063dd62ed3e90614d059030908890600401615593565b60206040518083038186803b158015614d1d57600080fd5b505afa158015614d31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614d559190615499565b10156138a857614d706001600160a01b0383168460006137ae565b6138a86001600160a01b038316846000196137ae565b6000734c517d4e2c851ca76d7ec94b805269df0f2201de6001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614dd757600080fd5b505af1158015614deb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e0f9190615499565b90506000614e3e670de0b6b3a764000061228a61271061228a600c5461344a888a61411b90919063ffffffff16565b9050614e48615275565b50604080516101008101825273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28152600080516020615b0b8339815191526020820152600b54600160281b900462ffffff168183015230606082015242608082015260a0810185905260c08101839052600060e0820152905163414bf38960e01b815273e592427a0aece92de3edee1f18e0157c058615649063414bf389908690614eeb908590600401615990565b6020604051808303818588803b158015614f0457600080fd5b505af1158015614f18573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190614f3d9190615499565b5073e592427a0aece92de3edee1f18e0157c058615646001600160a01b03166312210e8a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015614f8d57600080fd5b505af1158015614fa1573d6000803e3d6000fd5b5050505050505050565b6040516370a0823160e01b81526150539073e592427a0aece92de3edee1f18e0157c0586156490736dea81c8171d0ba574754ef6f8b412f2ed88c54d9081906370a0823190614ffe90309060040161557f565b60206040518083038186803b15801561501657600080fd5b505afa15801561502a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061504e9190615499565b614cd5565b600b546040516060916150bc91736dea81c8171d0ba574754ef6f8b412f2ed88c54d9162ffffff62010000820481169273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc292600160281b900490911690600080516020615b0b8339815191529060200161550e565b60408051601f1981840301815260a0830182528083523060208401819052428484015291516370a0823160e01b815290935073e592427a0aece92de3edee1f18e0157c058615649263c04b8d599290916060830191736dea81c8171d0ba574754ef6f8b412f2ed88c54d916370a08231916151399160040161557f565b60206040518083038186803b15801561515157600080fd5b505afa158015615165573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906151899190615499565b815260200160008152506040518263ffffffff1660e01b81526004016145569190615938565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106151f05782800160ff1982351617855561521d565b8280016001018555821561521d579182015b8281111561521d578235825591602001919060010190615202565b506141179291506152b9565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b5b8082111561411757600081556001016152ba565b803562ffffff811681146125b257600080fd5b6000602082840312156152f2578081fd5b8135613f7f81615ac7565b60006020828403121561530e578081fd5b8151613f7f81615ac7565b60006020828403121561532a578081fd5b8135613f7f81615adc565b600060208284031215615346578081fd5b8151613f7f81615adc565b60008060208385031215615363578081fd5b823567ffffffffffffffff8082111561537a578283fd5b818501915085601f83011261538d578283fd5b81358181111561539b578384fd5b8660208285010111156153ac578384fd5b60209290920196919550909350505050565b60006101208083850312156153d1578182fd5b6153da81615a74565b9050825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b600080600060608486031215615450578081fd5b61545a85856152ce565b925061546985602086016152ce565b915061547885604086016152ce565b90509250925092565b600060208284031215615492578081fd5b5035919050565b6000602082840312156154aa578081fd5b5051919050565b600080600080608085870312156154c6578081fd5b5050823594602084013594506040840135936060013592509050565b600081518084526154fa816020860160208601615a9b565b601f01601f19169290920160200192915050565b6bffffffffffffffffffffffff19606096871b811682526001600160e81b031960e896871b8116601484015294871b811660178301529290941b909216602b840152921b909116602e82015260420190565b60008251615572818460208701615a9b565b9190910192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b90815260200190565b600f93840b81529190920b6020820152604081019190915260600190565b600f94850b81529290930b60208301526040820152606081019190915260800190565b60006020825282602083015282846040840137818301604090810191909152601f909201601f19160101919050565b600060208252613f7f60208301846154e2565b6020808252600b908201526a085cdd1c985d1959da5cdd60aa1b604082015260600190565b602080825260059082015264085dd85b9d60da1b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252600b908201526a546f206d7563682044414960a81b604082015260600190565b6020808252600c908201526b216865616c7468636865636b60a01b604082015260600190565b6020808252600a9082015269043616e277420626520360b41b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b602080825260069082015265085d985d5b1d60d21b604082015260600190565b6020808252600790820152662173686172657360c81b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252600d908201526c546f6f204d616e79204269707360981b604082015260600190565b6020808252600b908201526a08585d5d1a1bdc9a5e995960aa1b604082015260600190565b6020808252600e908201526d4e6f7420656e6f7567682044414960901b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252600a9082015269085c1c9bdd1958dd195960b21b604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b600060208252825160a0602084015261595460c08401826154e2565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b81516001600160a01b03908116825260208084015182169083015260408084015162ffffff16908301526060808401518216908301526080808401519083015260a0838101519083015260c0808401519083015260e09283015116918101919091526101000190565b62ffffff91909116815260200190565b9182526001600160a01b0316602082015260400190565b9283526020830191909152604082015260600190565b93845260208401929092526040830152606082015260800190565b948552602085019390935260408401919091526060830152608082015260a00190565b60405181810167ffffffffffffffff81118282101715615a9357600080fd5b604052919050565b60005b83811015615ab6578181015183820152602001615a9e565b838111156149f25750506000910152565b6001600160a01b03811681146117bf57600080fd5b80151581146117bf57600080fdfe00000000000000000000000066017d22b0f8556afdd19fc67041899eb65a21bb0000000000000000000000006b175474e89094c44da98b954eedeac495271d0fa2646970667358221220dc84c75325c2826fa1fbbb116dcf4ef0a7a052fcb2df5e9195df2f697469c9eb64736f6c634300060c0033000000000000000000000000378cb52b00f9d0921cb46dfc099cff73b42419dc
Deployed Bytecode
0x6080604052600436106103a65760003560e01c8063748747e6116101e7578063ad09c2281161010d578063ec38a862116100a0578063f4eac0091161006f578063f4eac009146109b3578063fbfa77cf146109c8578063fcf2d0ad146109dd578063fef2acae146109f2576103ad565b8063ec38a8621461093e578063ed882c2b1461095e578063efbb5cb01461097e578063f017c92f14610993576103ad565b8063c7b9d530116100dc578063c7b9d530146108c9578063ce5494bb146108e9578063dd15c95e14610909578063eb4dc30414610929576103ad565b8063ad09c2281461086a578063b252720b1461088a578063b912e1ca1461089f578063c1a3d44c146108b4576103ad565b80638e6350e211610185578063a752c3ca11610154578063a752c3ca1461080b578063a85ef67814610820578063ac00ff2614610835578063aced166114610855576103ad565b80638e6350e2146107ac57806391397ab4146107c157806395e80c50146107e15780639ec5a894146107f6576103ad565b80637fb6085f116101c15780637fb6085f14610758578063802a59161461076d57806380d0e030146107825780638cdfe16614610797576103ad565b8063748747e6146106f8578063750521f514610718578063780022a014610738576103ad565b806328b7ccf7116102cc578063545ae8541161026a5780635fbeb25f116102395780635fbeb25f14610699578063650d1880146106ae5780636718835f146106ce578063695ec8da146106e3576103ad565b8063545ae8541461063a5780635641ec031461064f5780635ac90945146106645780635eff5b1014610679576103ad565b806336515795116102a657806336515795146105db57806339a172a8146105f0578063440368a3146106105780634641257d14610625576103ad565b806328b7ccf71461058657806329c480551461059b5780632e1a7d4d146105bb576103ad565b80630f969b87116103445780631f1fcd51116103135780631f1fcd51146105185780631fe4a6861461053a57806322f3e2d41461054f5780632582941014610571576103ad565b80630f969b871461049457806311bc8245146104b457806319e3437a146104d45780631d12f28b146104f6576103ad565b806306fdde031161038057806306fdde031461041f5780630b294723146104345780630b643781146104545780630d45d9be14610474576103ad565b806301681a62146103b257806303ee438c146103d4578063068196d4146103ff576103ad565b366103ad57005b600080fd5b3480156103be57600080fd5b506103d26103cd3660046152e1565b610a07565b005b3480156103e057600080fd5b506103e9610ba6565b6040516103f6919061564a565b60405180910390f35b34801561040b57600080fd5b506103d261041a3660046154b1565b610c34565b34801561042b57600080fd5b506103e9610e19565b34801561044057600080fd5b506103d261044f366004615481565b610e50565b34801561046057600080fd5b506103d261046f366004615481565b611045565b34801561048057600080fd5b506103d261048f366004615481565b611208565b3480156104a057600080fd5b506103d26104af366004615481565b61139c565b3480156104c057600080fd5b506103d26104cf3660046152e1565b611429565b3480156104e057600080fd5b506104e961152a565b6040516103f691906159f9565b34801561050257600080fd5b5061050b61153c565b6040516103f691906155d1565b34801561052457600080fd5b5061052d611542565b6040516103f6919061557f565b34801561054657600080fd5b5061052d611551565b34801561055b57600080fd5b50610564611560565b6040516103f691906155c6565b34801561057d57600080fd5b506103e9611602565b34801561059257600080fd5b5061050b611621565b3480156105a757600080fd5b506103d26105b6366004615481565b611627565b3480156105c757600080fd5b5061050b6105d6366004615481565b6117c2565b3480156105e757600080fd5b5061050b61181d565b3480156105fc57600080fd5b506103d261060b366004615481565b611823565b34801561061c57600080fd5b506103d26118a5565b34801561063157600080fd5b506103d2611ace565b34801561064657600080fd5b506103d2611fa7565b34801561065b57600080fd5b50610564612048565b34801561067057600080fd5b5061050b612051565b34801561068557600080fd5b506103d2610694366004615481565b612057565b3480156106a557600080fd5b5061050b6121eb565b3480156106ba57600080fd5b506105646106c9366004615481565b6121f1565b3480156106da57600080fd5b506105646122b5565b3480156106ef57600080fd5b5061050b6122be565b34801561070457600080fd5b506103d26107133660046152e1565b6123d3565b34801561072457600080fd5b506103d2610733366004615351565b61247e565b34801561074457600080fd5b5061050b610753366004615481565b612515565b34801561076457600080fd5b5061050b6125b8565b34801561077957600080fd5b5061050b6125be565b34801561078e57600080fd5b506105646125c4565b3480156107a357600080fd5b5061050b6125d2565b3480156107b857600080fd5b5061050b6125d8565b3480156107cd57600080fd5b506103d26107dc366004615481565b6125dd565b3480156107ed57600080fd5b5061050b61265f565b34801561080257600080fd5b5061052d612665565b34801561081757600080fd5b506104e9612674565b34801561082c57600080fd5b506103d2612685565b34801561084157600080fd5b506103d2610850366004615319565b61270c565b34801561086157600080fd5b5061052d6127f8565b34801561087657600080fd5b506103d2610885366004615319565b612807565b34801561089657600080fd5b5061052d6129b0565b3480156108ab57600080fd5b506104e96129c4565b3480156108c057600080fd5b5061050b6129d6565b3480156108d557600080fd5b506103d26108e43660046152e1565b612a57565b3480156108f557600080fd5b506103d26109043660046152e1565b612b02565b34801561091557600080fd5b506103d261092436600461543c565b612c4d565b34801561093557600080fd5b5061050b612e30565b34801561094a57600080fd5b506103d26109593660046152e1565b612ebf565b34801561096a57600080fd5b50610564610979366004615481565b613052565b34801561098a57600080fd5b5061050b613284565b34801561099f57600080fd5b506103d26109ae366004615481565b613463565b3480156109bf57600080fd5b5061050b6134e5565b3480156109d457600080fd5b5061052d6134eb565b3480156109e957600080fd5b506103d26134fa565b3480156109fe57600080fd5b5061050b61371f565b610a0f6138c4565b6001600160a01b0316336001600160a01b031614610a485760405162461bcd60e51b8152600401610a3f90615827565b60405180910390fd5b6006546001600160a01b0382811691161415610a765760405162461bcd60e51b8152600401610a3f90615682565b6002546001600160a01b0382811691161415610aa45760405162461bcd60e51b8152600401610a3f906157a8565b6060610aae613941565b905060005b8151811015610b0957818181518110610ac857fe5b60200260200101516001600160a01b0316836001600160a01b03161415610b015760405162461bcd60e51b8152600401610a3f906158be565b600101610ab3565b50610ba2610b156138c4565b6040516370a0823160e01b81526001600160a01b038516906370a0823190610b4190309060040161557f565b60206040518083038186803b158015610b5957600080fd5b505afa158015610b6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b919190615499565b6001600160a01b0385169190613946565b5050565b6000805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610c2c5780601f10610c0157610100808354040283529160200191610c2c565b820191906000526020600020905b815481529060010190602001808311610c0f57829003601f168201915b505050505081565b6003546001600160a01b0316331480610c655750610c506138c4565b6001600160a01b0316336001600160a01b0316145b80610d065750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015610cb957600080fd5b505afa158015610ccd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf191906152fd565b6001600160a01b0316336001600160a01b0316145b80610da75750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610d5a57600080fd5b505afa158015610d6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9291906152fd565b6001600160a01b0316336001600160a01b0316145b610dc35760405162461bcd60e51b8152600401610a3f90615827565b612710841115610de55760405162461bcd60e51b8152600401610a3f90615800565b60008211610e055760405162461bcd60e51b8152600401610a3f90615723565b600f93909355601091909155601155600e55565b6040805180820190915260208082527f53747261746567794c69717569747953746162696c697479506f6f6c4c5553449082015290565b6003546001600160a01b0316331480610e815750610e6c6138c4565b6001600160a01b0316336001600160a01b0316145b80610f225750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015610ed557600080fd5b505afa158015610ee9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0d91906152fd565b6001600160a01b0316336001600160a01b0316145b80610fc35750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610f7657600080fd5b505afa158015610f8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fae91906152fd565b6001600160a01b0316336001600160a01b0316145b610fdf5760405162461bcd60e51b8152600401610a3f90615827565b604051632e54bf9560e01b8152600080516020615aeb83398151915290632e54bf95906110109084906004016155d1565b600060405180830381600087803b15801561102a57600080fd5b505af115801561103e573d6000803e3d6000fd5b5050505050565b6003546001600160a01b031633148061107657506110616138c4565b6001600160a01b0316336001600160a01b0316145b806111175750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b1580156110ca57600080fd5b505afa1580156110de573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110291906152fd565b6001600160a01b0316336001600160a01b0316145b806111b85750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561116b57600080fd5b505afa15801561117f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a391906152fd565b6001600160a01b0316336001600160a01b0316145b6111d45760405162461bcd60e51b8152600401610a3f90615827565b604051635f788d6560e01b8152600080516020615aeb83398151915290635f788d6590611010908490600090600401615a09565b6003546001600160a01b031633148061123957506112246138c4565b6001600160a01b0316336001600160a01b0316145b806112da5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561128d57600080fd5b505afa1580156112a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c591906152fd565b6001600160a01b0316336001600160a01b0316145b8061137b5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561132e57600080fd5b505afa158015611342573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136691906152fd565b6001600160a01b0316336001600160a01b0316145b6113975760405162461bcd60e51b8152600401610a3f90615827565b600d55565b6003546001600160a01b03163314806113cd57506113b86138c4565b6001600160a01b0316336001600160a01b0316145b6113e95760405162461bcd60e51b8152600401610a3f90615827565b600a8190556040517fa68ba126373d04c004c5748c300c9fca12bd444b3d4332e261f3bd2bac4a86009061141e9083906155d1565b60405180910390a150565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561147757600080fd5b505afa15801561148b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114af91906152fd565b6001600160a01b0316336001600160a01b031614806114e657506114d16138c4565b6001600160a01b0316336001600160a01b0316145b6115025760405162461bcd60e51b8152600401610a3f90615827565b600180546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b600b54600160281b900462ffffff1681565b600a5481565b6006546001600160a01b031681565b6003546001600160a01b031681565b6002546040516339ebf82360e01b815260009182916001600160a01b03909116906339ebf8239061159590309060040161557f565b6101206040518083038186803b1580156115ae57600080fd5b505afa1580156115c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e691906153be565b6040015111806115fd575060006115fb613284565b115b905090565b604080518082019091526005815264302e342e3360d81b602082015290565b60085481565b6003546001600160a01b031633148061165857506116436138c4565b6001600160a01b0316336001600160a01b0316145b806116f95750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b1580156116ac57600080fd5b505afa1580156116c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e491906152fd565b6001600160a01b0316336001600160a01b0316145b8061179a5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561174d57600080fd5b505afa158015611761573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061178591906152fd565b6001600160a01b0316336001600160a01b0316145b6117b65760405162461bcd60e51b8152600401610a3f90615827565b6117bf81613965565b50565b6002546000906001600160a01b031633146117ef5760405162461bcd60e51b8152600401610a3f90615788565b60006117fa83613a2d565b600654909350909150611817906001600160a01b03163383613946565b50919050565b600f5481565b6003546001600160a01b0316331480611854575061183f6138c4565b6001600160a01b0316336001600160a01b0316145b6118705760405162461bcd60e51b8152600401610a3f90615827565b60078190556040517fbb2c369a0355a34b02ab5fce0643150c87e1c8dfe7c918d465591879f57948b19061141e9083906155d1565b6005546001600160a01b03163314806118c857506003546001600160a01b031633145b806118eb57506118d66138c4565b6001600160a01b0316336001600160a01b0316145b8061198c5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561193f57600080fd5b505afa158015611953573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197791906152fd565b6001600160a01b0316336001600160a01b0316145b80611a2d5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b1580156119e057600080fd5b505afa1580156119f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1891906152fd565b6001600160a01b0316336001600160a01b0316145b611a495760405162461bcd60e51b8152600401610a3f90615827565b6002546040805163bf3759b560e01b81529051611acc926001600160a01b03169163bf3759b5916004808301926020929190829003018186803b158015611a8f57600080fd5b505afa158015611aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac79190615499565b613c90565b565b6005546001600160a01b0316331480611af157506003546001600160a01b031633145b80611b145750611aff6138c4565b6001600160a01b0316336001600160a01b0316145b80611bb55750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015611b6857600080fd5b505afa158015611b7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba091906152fd565b6001600160a01b0316336001600160a01b0316145b80611c565750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015611c0957600080fd5b505afa158015611c1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4191906152fd565b6001600160a01b0316336001600160a01b0316145b611c725760405162461bcd60e51b8152600401610a3f90615827565b6000806000600260009054906101000a90046001600160a01b03166001600160a01b031663bf3759b56040518163ffffffff1660e01b815260040160206040518083038186803b158015611cc557600080fd5b505afa158015611cd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cfd9190615499565b600b5490915060009060ff1615611d5a576000611d18613dc1565b905082811015611d3357611d2c8382613f3d565b9350611d48565b82811115611d4857611d458184613f3d565b94505b611d528385613f3d565b915050611d6b565b611d6382613f86565b919550935090505b6002546040516339ebf82360e01b81526000916001600160a01b0316906339ebf82390611d9c90309060040161557f565b6101206040518083038186803b158015611db557600080fd5b505afa158015611dc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ded91906153be565b60c001516002546040516328766ebf60e21b81529192506001600160a01b03169063a1d9bafc90611e2690889088908790600401615a20565b602060405180830381600087803b158015611e4057600080fd5b505af1158015611e54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e789190615499565b9250611e8383613c90565b60015460ff168015611ea4575060015461010090046001600160a01b031615155b15611f565760015460405163c70fa00b60e01b81526101009091046001600160a01b03169063c70fa00b90611ee59088908890879089908890600401615a51565b60206040518083038186803b158015611efd57600080fd5b505afa158015611f11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f359190615335565b611f515760405162461bcd60e51b8152600401610a3f906156fd565b611f63565b6001805460ff1916811790555b7f4c0f499ffe6befa0ca7c826b0916cf87bea98de658013e76938489368d60d50985858486604051611f989493929190615a36565b60405180910390a15050505050565b611faf6138c4565b6001600160a01b0316336001600160a01b031614611fdf5760405162461bcd60e51b8152600401610a3f90615827565b6000336001600160a01b031647604051611ff89061557c565b60006040518083038185875af1925050503d8060008114612035576040519150601f19603f3d011682016040523d82523d6000602084013e61203a565b606091505b50509050806117bf57600080fd5b600b5460ff1681565b600e5481565b6003546001600160a01b031633148061208857506120736138c4565b6001600160a01b0316336001600160a01b0316145b806121295750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b1580156120dc57600080fd5b505afa1580156120f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211491906152fd565b6001600160a01b0316336001600160a01b0316145b806121ca5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561217d57600080fd5b505afa158015612191573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b591906152fd565b6001600160a01b0316336001600160a01b0316145b6121e65760405162461bcd60e51b8152600401610a3f90615827565b600c55565b600d5481565b6000806121fc613284565b9050600061220861371f565b90508061221a576000925050506122b0565b600e54612225614084565b1115612236576000925050506122b0565b601054811061224a576001925050506122b0565b600a8104841115612260576000925050506122b0565b600061226b82612515565b9050600061229061271061228a600f548761411b90919063ffffffff16565b90614155565b9050808211156122a75760019450505050506122b0565b60009450505050505b919050565b60015460ff1681565b60405163f5f1595d60e01b81526000906115fd90600080516020615aeb8339815191529063f5f1595d906122f690309060040161557f565b60206040518083038186803b15801561230e57600080fd5b505afa158015612322573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123469190615499565b6040516370a0823160e01b8152736dea81c8171d0ba574754ef6f8b412f2ed88c54d906370a082319061237d90309060040161557f565b60206040518083038186803b15801561239557600080fd5b505afa1580156123a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123cd9190615499565b90614197565b6003546001600160a01b031633148061240457506123ef6138c4565b6001600160a01b0316336001600160a01b0316145b6124205760405162461bcd60e51b8152600401610a3f90615827565b6001600160a01b03811661243357600080fd5b600580546001600160a01b0319166001600160a01b0383161790556040517f2f202ddb4a2e345f6323ed90f8fc8559d770a7abbbeee84dde8aca3351fe71549061141e90839061557f565b6003546001600160a01b03163314806124af575061249a6138c4565b6001600160a01b0316336001600160a01b0316145b6124cb5760405162461bcd60e51b8152600401610a3f90615827565b6124d7600083836151af565b507f300e67d5a415b6d015a471d9c7b95dd58f3e8290af965e84e0f845de2996dda6828260405161250992919061561b565b60405180910390a15050565b60006125b2670de0b6b3a764000061228a734c517d4e2c851ca76d7ec94b805269df0f2201de6001600160a01b0316630490be836040518163ffffffff1660e01b815260040160206040518083038186803b15801561257357600080fd5b505afa158015612587573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ab9190615499565b859061411b565b92915050565b60105481565b600c5481565b600b54610100900460ff1681565b60095481565b600090565b6003546001600160a01b031633148061260e57506125f96138c4565b6001600160a01b0316336001600160a01b0316145b61262a5760405162461bcd60e51b8152600401610a3f90615827565b60098190556040517fd94596337df4c2f0f44d30a7fc5db1c7bb60d9aca4185ed77c6fd96eb45ec2989061141e9083906155d1565b60075481565b6004546001600160a01b031681565b600b5462010000900462ffffff1681565b61268d6138c4565b6001600160a01b0316336001600160a01b0316146126bd5760405162461bcd60e51b8152600401610a3f90615827565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b15801561102a57600080fd5b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561275a57600080fd5b505afa15801561276e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279291906152fd565b6001600160a01b0316336001600160a01b031614806127c957506127b46138c4565b6001600160a01b0316336001600160a01b0316145b6127e55760405162461bcd60e51b8152600401610a3f90615827565b6001805460ff1916911515919091179055565b6005546001600160a01b031681565b6003546001600160a01b031633148061283857506128236138c4565b6001600160a01b0316336001600160a01b0316145b806128d95750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561288c57600080fd5b505afa1580156128a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c491906152fd565b6001600160a01b0316336001600160a01b0316145b8061297a5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561292d57600080fd5b505afa158015612941573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296591906152fd565b6001600160a01b0316336001600160a01b0316145b6129965760405162461bcd60e51b8152600401610a3f90615827565b600b80549115156101000261ff0019909216919091179055565b60015461010090046001600160a01b031681565b600b54600160401b900462ffffff1681565b6006546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612a0790309060040161557f565b60206040518083038186803b158015612a1f57600080fd5b505afa158015612a33573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115fd9190615499565b6003546001600160a01b0316331480612a885750612a736138c4565b6001600160a01b0316336001600160a01b0316145b612aa45760405162461bcd60e51b8152600401610a3f90615827565b6001600160a01b038116612ab757600080fd5b600380546001600160a01b0319166001600160a01b0383161790556040517f352ececae6d7d1e6d26bcf2c549dfd55be1637e9b22dc0cf3b71ddb36097a6b49061141e90839061557f565b6002546001600160a01b03163314612b1957600080fd5b6002546040805163fbfa77cf60e01b815290516001600160a01b039283169284169163fbfa77cf916004808301926020929190829003018186803b158015612b6057600080fd5b505afa158015612b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b9891906152fd565b6001600160a01b031614612bab57600080fd5b612bb4816141bc565b6006546040516370a0823160e01b81526117bf9183916001600160a01b03909116906370a0823190612bea90309060040161557f565b60206040518083038186803b158015612c0257600080fd5b505afa158015612c16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c3a9190615499565b6006546001600160a01b03169190613946565b6003546001600160a01b0316331480612c7e5750612c696138c4565b6001600160a01b0316336001600160a01b0316145b80612d1f5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015612cd257600080fd5b505afa158015612ce6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0a91906152fd565b6001600160a01b0316336001600160a01b0316145b80612dc05750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015612d7357600080fd5b505afa158015612d87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dab91906152fd565b6001600160a01b0316336001600160a01b0316145b612ddc5760405162461bcd60e51b8152600401610a3f90615827565b600b805464ffffff000019166201000062ffffff958616021767ffffff00000000001916600160281b93851693909302929092176affffff00000000000000001916600160401b9190931602919091179055565b604051621cdc4760e81b81526000906115fd90600080516020615aeb83398151915290631cdc470090612e6790309060040161557f565b60206040518083038186803b158015612e7f57600080fd5b505afa158015612e93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eb79190615499565b6123cd6129d6565b6003546001600160a01b03163314612ee95760405162461bcd60e51b8152600401610a3f9061565d565b6001600160a01b038116612efc57600080fd5b6002546004805460405163095ea7b360e01b81526001600160a01b039384169363095ea7b393612f339390911691600091016155ad565b602060405180830381600087803b158015612f4d57600080fd5b505af1158015612f61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f859190615335565b50600480546001600160a01b0319166001600160a01b038381169190911780835560025460405163095ea7b360e01b81529083169363095ea7b393612fd093169160001991016155ad565b602060405180830381600087803b158015612fea57600080fd5b505af1158015612ffe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130229190615335565b507fafbb66abf8f3b719799940473a4052a3717cdd8e40fb6c8a3faadab316b1a0698160405161141e919061557f565b600061305c611560565b613068575060006122b0565b613070615229565b6002546040516339ebf82360e01b81526001600160a01b03909116906339ebf823906130a090309060040161557f565b6101206040518083038186803b1580156130b957600080fd5b505afa1580156130cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130f191906153be565b905060006130fd613284565b60c08301519091506000613119613112612e30565b8490613f3d565b905080156131dc5761313c61271061228a600c548461411b90919063ffffffff16565b6040516307211ef760e01b815273ed279fdd11ca84beef15af5d39bb4d4bee23f0ca906307211ef7906131799060019060009087906004016155da565b60206040518083038186803b15801561319157600080fd5b505afa1580156131a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131c99190615499565b10156131dc5760009450505050506122b0565b6131e46142ed565b6131f55760009450505050506122b0565b600082841161320557600061320f565b61320f8484613f3d565b9050600d54811115613229576001955050505050506122b0565b60075460a086015161323c904290613f3d565b1015613250576000955050505050506122b0565b60085460a0860151613263904290613f3d565b1115613277576001955050505050506122b0565b5060009695505050505050565b6040516370a0823160e01b81526000908190600080516020615b0b833981519152906370a08231906132ba90309060040161557f565b60206040518083038186803b1580156132d257600080fd5b505afa1580156132e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061330a9190615499565b9050600080821161331c5760006133a9565b6040516307211ef760e01b815273ed279fdd11ca84beef15af5d39bb4d4bee23f0ca906307211ef7906133599060019060009087906004016155da565b60206040518083038186803b15801561337157600080fd5b505afa158015613385573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133a99190615499565b905061345c613450670de0b6b3a764000061228a734c517d4e2c851ca76d7ec94b805269df0f2201de6001600160a01b0316630490be836040518163ffffffff1660e01b815260040160206040518083038186803b15801561340a57600080fd5b505afa15801561341e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134429190615499565b61344a61371f565b9061411b565b6123cd836123cd612e30565b9250505090565b6003546001600160a01b0316331480613494575061347f6138c4565b6001600160a01b0316336001600160a01b0316145b6134b05760405162461bcd60e51b8152600401610a3f90615827565b60088190556040517f5430e11864ad7aa9775b07d12657fe52df9aa2ba734355bd8ef8747be2c800c59061141e9083906155d1565b60115481565b6002546001600160a01b031681565b6003546001600160a01b031633148061352b57506135166138c4565b6001600160a01b0316336001600160a01b0316145b806135cc5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561357f57600080fd5b505afa158015613593573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b791906152fd565b6001600160a01b0316336001600160a01b0316145b8061366d5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561362057600080fd5b505afa158015613634573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061365891906152fd565b6001600160a01b0316336001600160a01b0316145b6136895760405162461bcd60e51b8152600401610a3f90615827565b600b805460ff191660011790556002546040805163507257cd60e11b815290516001600160a01b039092169163a0e4af9a9160048082019260009290919082900301818387803b1580156136dc57600080fd5b505af11580156136f0573d6000803e3d6000fd5b50506040517f97e963041e952738788b9d4871d854d282065b8f90a464928d6528f2e9a4fd0b925060009150a1565b60405163389e92a560e01b81526000906115fd90600080516020615aeb8339815191529063389e92a59061375790309060040161557f565b60206040518083038186803b15801561376f57600080fd5b505afa158015613783573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137a79190615499565b4790614197565b8015806138365750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e906137e49030908690600401615593565b60206040518083038186803b1580156137fc57600080fd5b505afa158015613810573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138349190615499565b155b6138525760405162461bcd60e51b8152600401610a3f906158e2565b6138a88363095ea7b360e01b84846040516024016138719291906155ad565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614374565b505050565b60606138bc8484600085614403565b949350505050565b60025460408051635aa6e67560e01b815290516000926001600160a01b031691635aa6e675916004808301926020929190829003018186803b15801561390957600080fd5b505afa15801561391d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115fd91906152fd565b606090565b6138a88363a9059cbb60e01b84846040516024016138719291906155ad565b6040516370a0823160e01b81528190600080516020615b0b833981519152906370a082319061399890309060040161557f565b60206040518083038186803b1580156139b057600080fd5b505afa1580156139c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139e89190615499565b1015613a065760405162461bcd60e51b8152600401610a3f9061584c565b600b54610100900460ff1615613a2457613a1f816144c7565b6117bf565b6117bf816145a8565b6000806000613a3a6129d6565b9050838110613a50578360009250925050613c8b565b6000613a5c8583613f3d565b604051621cdc4760e81b8152909150600090600080516020615aeb83398151915290631cdc470090613a9290309060040161557f565b60206040518083038186803b158015613aaa57600080fd5b505afa158015613abe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae29190615499565b905080821115613bf2576040516370a0823160e01b8152600080516020615b0b833981519152906370a0823190613b1d90309060040161557f565b60206040518083038186803b158015613b3557600080fd5b505afa158015613b49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b6d9190615499565b15613b8a5760405162461bcd60e51b8152600401610a3f906156d8565b604051632e54bf9560e01b8152600080516020615aeb83398151915290632e54bf9590613bbb9084906004016155d1565b600060405180830381600087803b158015613bd557600080fd5b505af1158015613be9573d6000803e3d6000fd5b50505050613c56565b604051632e54bf9560e01b8152600080516020615aeb83398151915290632e54bf9590613c239085906004016155d1565b600060405180830381600087803b158015613c3d57600080fd5b505af1158015613c51573d6000803e3d6000fd5b505050505b6000613c606129d6565b905080871115613c7e57945084613c778782613f3d565b9450613c86565b869550600094505b505050505b915091565b6000613c9a61371f565b1115613ca857613ca86146e4565b6040516370a0823160e01b8152600090600080516020615b0b833981519152906370a0823190613cdc90309060040161557f565b60206040518083038186803b158015613cf457600080fd5b505afa158015613d08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d2c9190615499565b1115613d3a57613d3a6147f6565b6000613d446129d6565b905081811115610ba257600080516020615aeb833981519152635f788d65613d6c8385613f3d565b60006040518363ffffffff1660e01b8152600401613d8b929190615a09565b600060405180830381600087803b158015613da557600080fd5b505af1158015613db9573d6000803e3d6000fd5b505050505050565b604051621cdc4760e81b8152600090600080516020615aeb83398151915290632e54bf95908290631cdc470090613dfc90309060040161557f565b60206040518083038186803b158015613e1457600080fd5b505afa158015613e28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e4c9190615499565b6040518263ffffffff1660e01b8152600401613e6891906155d1565b600060405180830381600087803b158015613e8257600080fd5b505af1158015613e96573d6000803e3d6000fd5b50506040516370a0823160e01b815260009250600080516020615b0b83398151915291506370a0823190613ece90309060040161557f565b60206040518083038186803b158015613ee657600080fd5b505afa158015613efa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f1e9190615499565b90508015613f2f57613f2f81613965565b613f376129d6565b91505090565b6000613f7f83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506149f8565b9392505050565b6002546040516339ebf82360e01b81526000918291829182916001600160a01b03909116906339ebf82390613fbf90309060040161557f565b6101206040518083038186803b158015613fd857600080fd5b505afa158015613fec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061401091906153be565b60c00151905061401e614a24565b6000614028612e30565b9050818111156140475761403c8183613f3d565b945060009350614058565b600094506140558282613f3d565b93505b600061406c6140678888614197565b613a2d565b5090506140798782614c4f565b959794965050505050565b60008073f8d0ec04e94296773ce20efbeea82e76220cd5496001600160a01b0316639436dce46040518163ffffffff1660e01b815260040160206040518083038186803b1580156140d457600080fd5b505afa925050508015614104575060408051601f3d908101601f1916820190925261410191810190615499565b60015b614114575064e8d4a51000614117565b90505b5090565b60008261412a575060006125b2565b8282028284828161413757fe5b0414613f7f5760405162461bcd60e51b8152600401610a3f90615747565b6000613f7f83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614c65565b600082820183811015613f7f5760405162461bcd60e51b8152600401610a3f906156a1565b604051621cdc4760e81b8152600090600080516020615aeb83398151915290631cdc4700906141ef90309060040161557f565b60206040518083038186803b15801561420757600080fd5b505afa15801561421b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061423f9190615499565b11614249576117bf565b604051621cdc4760e81b8152600080516020615aeb83398151915290632e54bf95908290631cdc47009061428190309060040161557f565b60206040518083038186803b15801561429957600080fd5b505afa1580156142ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142d19190615499565b6040518263ffffffff1660e01b815260040161101091906155d1565b600073b5e1cacb567d98faadb60a1fd4820720141f064f6001600160a01b03166334a9e75c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561433c57600080fd5b505afa158015614350573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115fd9190615335565b60606143c9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166138ad9092919063ffffffff16565b8051909150156138a857808060200190518101906143e79190615335565b6138a85760405162461bcd60e51b8152600401610a3f90615874565b606061440e85614c9c565b61442a5760405162461bcd60e51b8152600401610a3f906157c9565b60006060866001600160a01b031685876040516144479190615560565b60006040518083038185875af1925050503d8060008114614484576040519150601f19603f3d011682016040523d82523d6000602084013e614489565b606091505b5091509150811561449d5791506138bc9050565b8051156144ad5780518082602001fd5b8360405162461bcd60e51b8152600401610a3f919061564a565b6144f473ed279fdd11ca84beef15af5d39bb4d4bee23f0ca600080516020615b0b83398151915283614cd5565b73ed279fdd11ca84beef15af5d39bb4d4bee23f0ca6001600160a01b031663a6417ed6600160008461453761271061228a600c548961411b90919063ffffffff16565b6040518563ffffffff1660e01b815260040161455694939291906155f8565b602060405180830381600087803b15801561457057600080fd5b505af1158015614584573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba29190615499565b6145d573e592427a0aece92de3edee1f18e0157c05861564600080516020615b0b83398151915283614cd5565b6145dd615275565b6040805161010081018252600080516020615b0b83398151915281526006546001600160a01b03166020820152600b54600160401b900462ffffff169181019190915230606082015242608082015260a08101839052600c5460c082019061464e906127109061228a90879061411b565b8152600060209091015260405163414bf38960e01b815290915073e592427a0aece92de3edee1f18e0157c058615649063414bf38990614692908490600401615990565b602060405180830381600087803b1580156146ac57600080fd5b505af11580156146c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138a89190615499565b604051621cdc4760e81b8152600090600080516020615aeb83398151915290631cdc47009061471790309060040161557f565b60206040518083038186803b15801561472f57600080fd5b505afa158015614743573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147679190615499565b11156147d257604051632e54bf9560e01b8152600080516020615aeb83398151915290632e54bf959061479f906000906004016155d1565b600060405180830381600087803b1580156147b957600080fd5b505af11580156147cd573d6000803e3d6000fd5b505050505b60006147e047601154614c4f565b9050806147ed5750611acc565b6117bf81614d86565b6040516370a0823160e01b8152600090600080516020615b0b833981519152906370a082319061482a90309060040161557f565b60206040518083038186803b15801561484257600080fd5b505afa158015614856573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061487a9190615499565b9050600061489961271061228a600c548561411b90919063ffffffff16565b6040516307211ef760e01b815290915060009073ed279fdd11ca84beef15af5d39bb4d4bee23f0ca906307211ef7906148db90600190859088906004016155da565b60206040518083038186803b1580156148f357600080fd5b505afa158015614907573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061492b9190615499565b90508181106138a85761496173ed279fdd11ca84beef15af5d39bb4d4bee23f0ca600080516020615b0b83398151915285614cd5565b604051635320bf6b60e11b815273ed279fdd11ca84beef15af5d39bb4d4bee23f0ca9063a6417ed6906149a090600190600090889088906004016155f8565b602060405180830381600087803b1580156149ba57600080fd5b505af11580156149ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149f29190615499565b50505050565b60008184841115614a1c5760405162461bcd60e51b8152600401610a3f919061564a565b505050900390565b604051621cdc4760e81b8152600090600080516020615aeb83398151915290631cdc470090614a5790309060040161557f565b60206040518083038186803b158015614a6f57600080fd5b505afa158015614a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614aa79190615499565b1115614b1257604051632e54bf9560e01b8152600080516020615aeb83398151915290632e54bf9590614adf906000906004016155d1565b600060405180830381600087803b158015614af957600080fd5b505af1158015614b0d573d6000803e3d6000fd5b505050505b6040516370a0823160e01b8152600090736dea81c8171d0ba574754ef6f8b412f2ed88c54d906370a0823190614b4c90309060040161557f565b60206040518083038186803b158015614b6457600080fd5b505afa158015614b78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b9c9190615499565b1115614baa57614baa614fab565b478015614bba57614bba81614d86565b6040516370a0823160e01b8152600090600080516020615b0b833981519152906370a0823190614bee90309060040161557f565b60206040518083038186803b158015614c0657600080fd5b505afa158015614c1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c3e9190615499565b90508015610ba257610ba281613965565b6000818310614c5e5781613f7f565b5090919050565b60008183614c865760405162461bcd60e51b8152600401610a3f919061564a565b506000838581614c9257fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906138bc575050151592915050565b604051636eb1769f60e11b815281906001600160a01b0384169063dd62ed3e90614d059030908890600401615593565b60206040518083038186803b158015614d1d57600080fd5b505afa158015614d31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614d559190615499565b10156138a857614d706001600160a01b0383168460006137ae565b6138a86001600160a01b038316846000196137ae565b6000734c517d4e2c851ca76d7ec94b805269df0f2201de6001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614dd757600080fd5b505af1158015614deb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e0f9190615499565b90506000614e3e670de0b6b3a764000061228a61271061228a600c5461344a888a61411b90919063ffffffff16565b9050614e48615275565b50604080516101008101825273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28152600080516020615b0b8339815191526020820152600b54600160281b900462ffffff168183015230606082015242608082015260a0810185905260c08101839052600060e0820152905163414bf38960e01b815273e592427a0aece92de3edee1f18e0157c058615649063414bf389908690614eeb908590600401615990565b6020604051808303818588803b158015614f0457600080fd5b505af1158015614f18573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190614f3d9190615499565b5073e592427a0aece92de3edee1f18e0157c058615646001600160a01b03166312210e8a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015614f8d57600080fd5b505af1158015614fa1573d6000803e3d6000fd5b5050505050505050565b6040516370a0823160e01b81526150539073e592427a0aece92de3edee1f18e0157c0586156490736dea81c8171d0ba574754ef6f8b412f2ed88c54d9081906370a0823190614ffe90309060040161557f565b60206040518083038186803b15801561501657600080fd5b505afa15801561502a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061504e9190615499565b614cd5565b600b546040516060916150bc91736dea81c8171d0ba574754ef6f8b412f2ed88c54d9162ffffff62010000820481169273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc292600160281b900490911690600080516020615b0b8339815191529060200161550e565b60408051601f1981840301815260a0830182528083523060208401819052428484015291516370a0823160e01b815290935073e592427a0aece92de3edee1f18e0157c058615649263c04b8d599290916060830191736dea81c8171d0ba574754ef6f8b412f2ed88c54d916370a08231916151399160040161557f565b60206040518083038186803b15801561515157600080fd5b505afa158015615165573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906151899190615499565b815260200160008152506040518263ffffffff1660e01b81526004016145569190615938565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106151f05782800160ff1982351617855561521d565b8280016001018555821561521d579182015b8281111561521d578235825591602001919060010190615202565b506141179291506152b9565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b5b8082111561411757600081556001016152ba565b803562ffffff811681146125b257600080fd5b6000602082840312156152f2578081fd5b8135613f7f81615ac7565b60006020828403121561530e578081fd5b8151613f7f81615ac7565b60006020828403121561532a578081fd5b8135613f7f81615adc565b600060208284031215615346578081fd5b8151613f7f81615adc565b60008060208385031215615363578081fd5b823567ffffffffffffffff8082111561537a578283fd5b818501915085601f83011261538d578283fd5b81358181111561539b578384fd5b8660208285010111156153ac578384fd5b60209290920196919550909350505050565b60006101208083850312156153d1578182fd5b6153da81615a74565b9050825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b600080600060608486031215615450578081fd5b61545a85856152ce565b925061546985602086016152ce565b915061547885604086016152ce565b90509250925092565b600060208284031215615492578081fd5b5035919050565b6000602082840312156154aa578081fd5b5051919050565b600080600080608085870312156154c6578081fd5b5050823594602084013594506040840135936060013592509050565b600081518084526154fa816020860160208601615a9b565b601f01601f19169290920160200192915050565b6bffffffffffffffffffffffff19606096871b811682526001600160e81b031960e896871b8116601484015294871b811660178301529290941b909216602b840152921b909116602e82015260420190565b60008251615572818460208701615a9b565b9190910192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b90815260200190565b600f93840b81529190920b6020820152604081019190915260600190565b600f94850b81529290930b60208301526040820152606081019190915260800190565b60006020825282602083015282846040840137818301604090810191909152601f909201601f19160101919050565b600060208252613f7f60208301846154e2565b6020808252600b908201526a085cdd1c985d1959da5cdd60aa1b604082015260600190565b602080825260059082015264085dd85b9d60da1b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252600b908201526a546f206d7563682044414960a81b604082015260600190565b6020808252600c908201526b216865616c7468636865636b60a01b604082015260600190565b6020808252600a9082015269043616e277420626520360b41b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b602080825260069082015265085d985d5b1d60d21b604082015260600190565b6020808252600790820152662173686172657360c81b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252600d908201526c546f6f204d616e79204269707360981b604082015260600190565b6020808252600b908201526a08585d5d1a1bdc9a5e995960aa1b604082015260600190565b6020808252600e908201526d4e6f7420656e6f7567682044414960901b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252600a9082015269085c1c9bdd1958dd195960b21b604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b600060208252825160a0602084015261595460c08401826154e2565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b81516001600160a01b03908116825260208084015182169083015260408084015162ffffff16908301526060808401518216908301526080808401519083015260a0838101519083015260c0808401519083015260e09283015116918101919091526101000190565b62ffffff91909116815260200190565b9182526001600160a01b0316602082015260400190565b9283526020830191909152604082015260600190565b93845260208401929092526040830152606082015260800190565b948552602085019390935260408401919091526060830152608082015260a00190565b60405181810167ffffffffffffffff81118282101715615a9357600080fd5b604052919050565b60005b83811015615ab6578181015183820152602001615a9e565b838111156149f25750506000910152565b6001600160a01b03811681146117bf57600080fd5b80151581146117bf57600080fdfe00000000000000000000000066017d22b0f8556afdd19fc67041899eb65a21bb0000000000000000000000006b175474e89094c44da98b954eedeac495271d0fa2646970667358221220dc84c75325c2826fa1fbbb116dcf4ef0a7a052fcb2df5e9195df2f697469c9eb64736f6c634300060c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000378cb52b00f9d0921cb46dfc099cff73b42419dc
-----Decoded View---------------
Arg [0] : _vault (address): 0x378cb52b00F9D0921cb46dFc099CFf73b42419dC
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000378cb52b00f9d0921cb46dfc099cff73b42419dc
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 29 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ 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.