Contract Overview
My Name Tag:
Not Available
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
Contract Name:
StrategyCurveTricrypto
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.6.12; pragma experimental ABIEncoderV2; // These are the core Yearn libraries import "IERC20.sol"; import "SafeMath.sol"; import "Address.sol"; import "SafeERC20.sol"; import "Math.sol"; import { IGauge, IGaugeFactory, ICurveFi } from "curve.sol"; import { IUniswapV2Router02 } from "uniswap.sol"; import { BaseStrategy, StrategyParams } from "BaseStrategy.sol"; abstract contract StrategyCurveBase is BaseStrategy { using SafeERC20 for IERC20; using Address for address; using SafeMath for uint256; /* ========== STATE VARIABLES ========== */ // these should stay the same across different wants. // Curve stuff IGauge public constant gauge = IGauge(0x555766f3da968ecBefa690Ffd49A2Ac02f47aa5f); // Curve gauge contract, most are tokenized, held by strategy IGaugeFactory public constant gaugeFactory = IGaugeFactory(0xabC000d88f23Bb45525E447528DBF656A9D55bf5); // keepCRV stuff uint256 public keepCRV; // the percentage of CRV we re-lock for boost (in basis points) uint256 internal constant FEE_DENOMINATOR = 10000; // this means all of our fee values are in basis points IERC20 public constant crv = IERC20(0x11cDb42B0EB46D95f990BeDD4695A6e3fA034978); bool internal forceHarvestTriggerOnce; // only set this to true externally when we want to trigger our keepers to harvest for us uint256 public creditThreshold; // amount of credit in underlying tokens that will automatically trigger a harvest string internal stratName; // set our strategy name here /* ========== CONSTRUCTOR ========== */ constructor(address _vault) public BaseStrategy(_vault) {} /* ========== VIEWS ========== */ function name() external view override returns (string memory) { return stratName; } function stakedBalance() public view returns (uint256) { return gauge.balanceOf(address(this)); } function balanceOfWant() public view returns (uint256) { return want.balanceOf(address(this)); } function estimatedTotalAssets() public view override returns (uint256) { return balanceOfWant().add(stakedBalance()); } /* ========== MUTATIVE FUNCTIONS ========== */ // these should stay the same across different wants. function adjustPosition(uint256 _debtOutstanding) internal override { if (emergencyExit) { return; } // Send all of our LP tokens to deposit to the gauge if we have any uint256 _toInvest = balanceOfWant(); if (_toInvest > 0) { gauge.deposit(_toInvest); } } function liquidatePosition(uint256 _amountNeeded) internal override returns (uint256 _liquidatedAmount, uint256 _loss) { uint256 _wantBal = balanceOfWant(); if (_amountNeeded > _wantBal) { // check if we have enough free funds to cover the withdrawal uint256 _stakedBal = stakedBalance(); if (_stakedBal > 0) { gauge.withdraw( Math.min(_stakedBal, _amountNeeded.sub(_wantBal)) ); } uint256 _withdrawnBal = balanceOfWant(); _liquidatedAmount = Math.min(_amountNeeded, _withdrawnBal); _loss = _amountNeeded.sub(_liquidatedAmount); } else { // we have enough balance to cover the liquidation available return (_amountNeeded, 0); } } // fire sale, get rid of it all! function liquidateAllPositions() internal override returns (uint256) { uint256 _stakedBal = stakedBalance(); if (_stakedBal > 0) { // don't bother withdrawing zero gauge.withdraw(_stakedBal); } return balanceOfWant(); } function _claimRewards() internal { gaugeFactory.mint(address(gauge)); } function claimRewards() external onlyVaultManagers { // Claims any pending CRV // // Mints claimable CRV from the factory gauge. Reward tokens are sent to `msg.sender` // The method claim_rewards() from the old gauge now only applies to third-party tokens. // There are no third-party tokens in this strategy. _claimRewards(); } function prepareMigration(address _newStrategy) internal override { // Withdraw LP tokens from the gauge. The transfer to the new strategy is done // by migrate() in BaseStrategy.sol uint256 _stakedBal = stakedBalance(); if (_stakedBal > 0) { gauge.withdraw(_stakedBal); } } function protectedTokens() internal view override returns (address[] memory) {} /* ========== SETTERS ========== */ // These functions are useful for setting parameters of the strategy that may need to be adjusted. // Set the amount of CRV to be locked in Yearn's veCRV voter from each harvest. Default is 10%. function setKeepCRV(uint256 _keepCRV) external onlyEmergencyAuthorized { require(_keepCRV <= 10_000); keepCRV = _keepCRV; } // Credit threshold is in want token, and will trigger a harvest if credit is large enough. function setCreditThreshold(uint256 _creditThreshold) external onlyEmergencyAuthorized { creditThreshold = _creditThreshold; } // This allows us to manually harvest with our keeper as needed function setForceHarvestTriggerOnce(bool _forceHarvestTriggerOnce) external onlyEmergencyAuthorized { forceHarvestTriggerOnce = _forceHarvestTriggerOnce; } } contract StrategyCurveTricrypto is StrategyCurveBase { /* ========== STATE VARIABLES ========== */ // these will likely change across different wants. // Curve stuff ICurveFi public constant curve = ICurveFi(0x960ea3e3C7FB317332d990873d354E18d7645590); // This is our pool specific to this vault. // we use these to deposit to our curve pool address public targetToken; // this is the token we sell into, WETH, WBTC, or fUSDT IERC20 internal constant wbtc = IERC20(0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f); IERC20 internal constant weth = IERC20(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1); IERC20 internal constant usdt = IERC20(0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9); IUniswapV2Router02 internal constant router = IUniswapV2Router02(0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506); // this is the router we swap with, sushi address public constant voter = 0x6346282DB8323A54E840c6C772B4399C9c655C0d; // sms /* ========== CONSTRUCTOR ========== */ constructor(address _vault, string memory _name) public StrategyCurveBase(_vault) { // You can set these parameters on deployment to whatever you want maxReportDelay = 2 days; // 2 days in seconds healthCheck = 0x32059ccE723b4DD15dD5cb2a5187f814e6c470bC; // arbitrum healthcheck contract // these are our standard approvals. want = Curve LP token want.approve(address(gauge), type(uint256).max); crv.approve(address(router), type(uint256).max); // set our strategy's name stratName = _name; // these are our approvals and path specific to this contract wbtc.approve(address(curve), type(uint256).max); weth.approve(address(curve), type(uint256).max); usdt.approve(address(curve), type(uint256).max); //'targetToken' is the token with the least impact on the curve pool at the time of deposit // or the one with the biggest bonus. 'targetToken' is updated by yearn when granted by // market conditions. We start off with usdt. targetToken = address(usdt); } /* ========== MUTATIVE FUNCTIONS ========== */ // these will likely change across different wants. function prepareReturn(uint256 _debtOutstanding) internal override returns ( uint256 _profit, uint256 _loss, uint256 _debtPayment ) { // Claim and get a fresh snapshot of the strategy's CRV balance _claimRewards(); uint256 crvBalance = crv.balanceOf(address(this)); // Sell CRV if we have any if (crvBalance > 0) { // keep some of our CRV to increase our boost uint256 sendToVoter = crvBalance.mul(keepCRV).div(FEE_DENOMINATOR); if (keepCRV > 0) { crv.safeTransfer(voter, sendToVoter); } // check our balance again after transferring some crv to our voter crvBalance = crv.balanceOf(address(this)); // sell the rest of our CRV if (crvBalance > 0) { _sell(crvBalance); } } uint256 wethBalance = weth.balanceOf(address(this)); uint256 wbtcBalance = wbtc.balanceOf(address(this)); uint256 usdtBalance = usdt.balanceOf(address(this)); // deposit our balance to Curve if we have any if (wethBalance > 0 || wbtcBalance > 0 || usdtBalance > 0) { curve.add_liquidity([usdtBalance, wbtcBalance, wethBalance], 0); } // debtOustanding will only be > 0 in the event of revoking or if we need to rebalance from a withdrawal or lowering the debtRatio uint256 stakedBal = stakedBalance(); if (_debtOutstanding > 0) { if (stakedBal > 0) { // don't bother withdrawing if we don't have staked funds gauge.withdraw(Math.min(stakedBal, _debtOutstanding)); } uint256 _withdrawnBal = balanceOfWant(); _debtPayment = Math.min(_debtOutstanding, _withdrawnBal); } // serious loss should never happen, but if it does (for instance, if Curve is hacked), let's record it accurately uint256 assets = estimatedTotalAssets(); uint256 debt = vault.strategies(address(this)).totalDebt; // if assets are greater than debt, things are working great! if (assets > debt) { _profit = assets.sub(debt); uint256 _wantBal = balanceOfWant(); if (_profit.add(_debtPayment) > _wantBal) { // this should only be hit following donations to strategy liquidateAllPositions(); } } // if assets are less than debt, we are in trouble else { _loss = debt.sub(assets); } // we're done harvesting, so reset our trigger if we used it forceHarvestTriggerOnce = false; } // Sells our CRV for WETH or targetToken on sushi function _sell(uint256 _amount) internal { address[] memory path; if (targetToken == address(weth)) { path = new address[](2); path[0] = address(crv); path[1] = address(weth); } else { path = new address[](3); path[0] = address(crv); path[1] = address(weth); path[2] = targetToken; } IUniswapV2Router02(router).swapExactTokensForTokens( _amount, uint256(0), path, address(this), block.timestamp ); } /* ========== KEEP3RS ========== */ function harvestTrigger(uint256 callCostinEth) 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)); // harvest no matter what once we reach our maxDelay if (block.timestamp.sub(params.lastReport) > maxReportDelay) { return true; } // harvest our credit if it's above our threshold if (vault.creditAvailable() > creditThreshold) { return true; } // trigger if we want to manually harvest if (forceHarvestTriggerOnce) { return true; } // otherwise, we don't harvest return false; } // convert our keeper's eth cost into want, we don't need this anymore since we don't use baseStrategy harvestTrigger function ethToWant(uint256 _ethAmount) public view override returns (uint256) { return _ethAmount; } /* ========== SETTERS ========== */ // These functions are useful for setting parameters of the strategy that may need to be adjusted. // Set optimal token to sell harvested funds for depositing to Curve. // Default is USDT, but can be set to WETH or WBTC as needed by strategist or governance. function setOptimal(uint256 _optimal) external onlyEmergencyAuthorized { if (_optimal == 0) { targetToken = address(weth); } else if (_optimal == 1) { targetToken = address(wbtc); } else if (_optimal == 2) { targetToken = address(usdt); } else { revert("incorrect token"); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @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; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.2; /** * @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); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import "IERC20.sol"; import "SafeMath.sol"; import "Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using 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"); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.6.12; pragma experimental ABIEncoderV2; interface IGauge { function deposit(uint256) external; function balanceOf(address) external view returns (uint256); function withdraw(uint256) external; function claimable_tokens(address) external returns (uint256); } interface IGaugeFactory { function mint(address _gauge) external; } interface ICurveFi { function add_liquidity( // 3pool uint256[3] calldata amounts, uint256 min_mint_amount ) external payable; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.6.12; pragma experimental ABIEncoderV2; interface IUniswapV2Router01 { function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidity( address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) external returns ( uint256 amountA, uint256 amountB, uint256 liquidity ); function addLiquidityETH( address token, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external payable returns ( uint256 amountToken, uint256 amountETH, uint256 liquidity ); function removeLiquidity( address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) external returns (uint256 amountA, uint256 amountB); function removeLiquidityETH( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external returns (uint256 amountToken, uint256 amountETH); function removeLiquidityWithPermit( address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint256 amountA, uint256 amountB); function removeLiquidityETHWithPermit( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint256 amountToken, uint256 amountETH); function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapTokensForExactTokens( uint256 amountOut, uint256 amountInMax, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapExactETHForTokens( uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external payable returns (uint256[] memory amounts); function swapTokensForExactETH( uint256 amountOut, uint256 amountInMax, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapExactTokensForETH( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapETHForExactTokens( uint256 amountOut, address[] calldata path, address to, uint256 deadline ) external payable returns (uint256[] memory amounts); function quote( uint256 amountA, uint256 reserveA, uint256 reserveB ) external pure returns (uint256 amountB); function getAmountOut( uint256 amountIn, uint256 reserveIn, uint256 reserveOut ) external pure returns (uint256 amountOut); function getAmountIn( uint256 amountOut, uint256 reserveIn, uint256 reserveOut ) external pure returns (uint256 amountIn); function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts); function getAmountsIn(uint256 amountOut, address[] calldata path) external view returns (uint256[] memory amounts); } interface IUniswapV2Router02 is IUniswapV2Router01 { function removeLiquidityETHSupportingFeeOnTransferTokens( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external returns (uint256 amountETH); function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint256 amountETH); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external; function swapExactETHForTokensSupportingFeeOnTransferTokens( uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external payable; function swapExactTokensForETHSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; pragma experimental ABIEncoderV2; import "IERC20.sol"; import "SafeERC20.sol"; import "SafeMath.sol"; struct StrategyParams { uint256 performanceFee; uint256 activation; uint256 debtRatio; uint256 minDebtPerHarvest; uint256 maxDebtPerHarvest; uint256 lastReport; uint256 totalDebt; uint256 totalGain; uint256 totalLoss; } 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); } /** * This interface is here for the keeper bot to use. */ interface StrategyAPI { function name() external view returns (string memory); function vault() external view returns (address); function want() external view returns (address); function apiVersion() external pure returns (string memory); function keeper() external view returns (address); function isActive() external view returns (bool); function delegatedAssets() external view returns (uint256); function estimatedTotalAssets() external view returns (uint256); function tendTrigger(uint256 callCost) external view returns (bool); function tend() external; function harvestTrigger(uint256 callCost) external view returns (bool); function harvest() external; event Harvested(uint256 profit, uint256 loss, uint256 debtPayment, uint256 debtOutstanding); } interface HealthCheck { function check( uint256 profit, uint256 loss, uint256 debtPayment, uint256 debtOutstanding, uint256 totalDebt ) external view returns (bool); } /** * @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))); } } abstract contract BaseStrategyInitializable is BaseStrategy { bool public isOriginal = true; event Cloned(address indexed clone); constructor(address _vault) public BaseStrategy(_vault) {} function initialize( address _vault, address _strategist, address _rewards, address _keeper ) external virtual { _initialize(_vault, _strategist, _rewards, _keeper); } function clone(address _vault) external returns (address) { require(isOriginal, "!clone"); return this.clone(_vault, msg.sender, msg.sender, msg.sender); } function clone( address _vault, address _strategist, address _rewards, address _keeper ) external returns (address newStrategy) { // Copied from https://github.com/optionality/clone-factory/blob/master/contracts/CloneFactory.sol bytes20 addressBytes = bytes20(address(this)); assembly { // EIP-1167 bytecode let clone_code := mload(0x40) mstore(clone_code, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(clone_code, 0x14), addressBytes) mstore(add(clone_code, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) newStrategy := create(0, clone_code, 0x37) } BaseStrategyInitializable(newStrategy).initialize(_vault, _strategist, _rewards, _keeper); emit Cloned(newStrategy); } }
{ "evmVersion": "istanbul", "optimizer": { "enabled": true, "runs": 200 }, "libraries": { "StrategyCurveTricrypto.sol": {} }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
[{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"string","name":"_name","type":"string"}],"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":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"creditThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"crv","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"curve","outputs":[{"internalType":"contract ICurveFi","name":"","type":"address"}],"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":[],"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":[{"internalType":"uint256","name":"_ethAmount","type":"uint256"}],"name":"ethToWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gauge","outputs":[{"internalType":"contract IGauge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gaugeFactory","outputs":[{"internalType":"contract IGaugeFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"callCostinEth","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":"keepCRV","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxReportDelay","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":"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":"_creditThreshold","type":"uint256"}],"name":"setCreditThreshold","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":"bool","name":"_forceHarvestTriggerOnce","type":"bool"}],"name":"setForceHarvestTriggerOnce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_healthCheck","type":"address"}],"name":"setHealthCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_keepCRV","type":"uint256"}],"name":"setKeepCRV","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":"_delay","type":"uint256"}],"name":"setMinReportDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_optimal","type":"uint256"}],"name":"setOptimal","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":[],"name":"stakedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategist","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"targetToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":"vault","outputs":[{"internalType":"contract VaultAPI","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voter","outputs":[{"internalType":"address","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"}]
Contract Creation Code
60806040523480156200001157600080fd5b5060405162004ab738038062004ab783398101604081905262000034916200098c565b81806200004481338080620003fa565b50506202a30060085560018054610100600160a81b0319167432059cce723b4dd15dd5cb2a5187f814e6c470bc0017905560065460405163095ea7b360e01b81526001600160a01b039091169063095ea7b390620000bf9073555766f3da968ecbefa690ffd49a2ac02f47aa5f906000199060040162000ab8565b602060405180830381600087803b158015620000da57600080fd5b505af1158015620000ef573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000115919062000a45565b5060405163095ea7b360e01b81527311cdb42b0eb46d95f990bedd4695a6e3fa0349789063095ea7b3906200016790731b02da8cb0d097eb8d57a175b88c7d8b47997506906000199060040162000ab8565b602060405180830381600087803b1580156200018257600080fd5b505af115801562000197573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001bd919062000a45565b508051620001d390600f906020840190620008ad565b5060405163095ea7b360e01b8152732f2a2543b76a4166549f7aab2e75bef0aefc5b0f9063095ea7b390620002259073960ea3e3c7fb317332d990873d354e18d7645590906000199060040162000ab8565b602060405180830381600087803b1580156200024057600080fd5b505af115801562000255573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200027b919062000a45565b5060405163095ea7b360e01b81527382af49447d8a07e3bd95bd0d56f35241523fbab19063095ea7b390620002cd9073960ea3e3c7fb317332d990873d354e18d7645590906000199060040162000ab8565b602060405180830381600087803b158015620002e857600080fd5b505af1158015620002fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000323919062000a45565b5060405163095ea7b360e01b815273fd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb99063095ea7b390620003759073960ea3e3c7fb317332d990873d354e18d7645590906000199060040162000ab8565b602060405180830381600087803b1580156200039057600080fd5b505af1158015620003a5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003cb919062000a45565b5050601080546001600160a01b03191673fd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb91790555062000c4e565b6006546001600160a01b0316156200042f5760405162461bcd60e51b8152600401620004269062000b06565b60405180910390fd5b600280546001600160a01b0319166001600160a01b03868116919091179182905560408051637e062a3560e11b81529051929091169163fc0c546a91600480820192602092909190829003018186803b1580156200048c57600080fd5b505afa158015620004a1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c7919062000967565b600680546001600160a01b0319166001600160a01b03928316179081905562000501911685600019620005de602090811b6200271d17901c565b600380546001600160a01b038086166001600160a01b03199283161790925560048054858416908316178082556005805486861694169390931790925560006007819055620151806008556064600955600a5560025460405163095ea7b360e01b81529084169363095ea7b3936200058193911691600019910162000ab8565b602060405180830381600087803b1580156200059c57600080fd5b505af1158015620005b1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005d7919062000a45565b5050505050565b8015806200066d5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e9062000617903090869060040162000a9e565b60206040518083038186803b1580156200063057600080fd5b505afa15801562000645573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200066b919062000a67565b155b6200068c5760405162461bcd60e51b8152600401620004269062000bbe565b620006e78363095ea7b360e01b8484604051602401620006ae92919062000ab8565b60408051808303601f190181529190526020810180516001600160e01b0319939093166001600160e01b0393841617905290620006ec16565b505050565b606062000748826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200078860201b6200281c179092919060201c565b805190915015620006e7578080602001905181019062000769919062000a45565b620006e75760405162461bcd60e51b8152600401620004269062000b74565b6060620007998484600085620007a1565b949350505050565b6060620007ae8562000873565b620007cd5760405162461bcd60e51b8152600401620004269062000b3d565b60006060866001600160a01b03168587604051620007ec919062000a80565b60006040518083038185875af1925050503d80600081146200082b576040519150601f19603f3d011682016040523d82523d6000602084013e62000830565b606091505b5091509150811562000846579150620007999050565b805115620008575780518082602001fd5b8360405162461bcd60e51b815260040162000426919062000ad1565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159062000799575050151592915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620008f057805160ff191683800117855562000920565b8280016001018555821562000920579182015b828111156200092057825182559160200191906001019062000903565b506200092e92915062000932565b5090565b5b808211156200092e576000815560010162000933565b80516001600160a01b03811681146200096157600080fd5b92915050565b60006020828403121562000979578081fd5b62000985838362000949565b9392505050565b600080604083850312156200099f578081fd5b620009ab848462000949565b60208401519092506001600160401b0380821115620009c8578283fd5b818501915085601f830112620009dc578283fd5b815181811115620009eb578384fd5b604051601f8201601f19168101602001838111828210171562000a0c578586fd5b60405281815283820160200188101562000a24578485fd5b62000a3782602083016020870162000c1b565b809450505050509250929050565b60006020828403121562000a57578081fd5b8151801515811462000985578182fd5b60006020828403121562000a79578081fd5b5051919050565b6000825162000a9481846020870162000c1b565b9190910192915050565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b600060208252825180602084015262000af281604085016020870162000c1b565b601f01601f19169190910160400192915050565b6020808252601c908201527f537472617465677920616c726561647920696e697469616c697a656400000000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000606082015260800190565b60005b8381101562000c3857818101518382015260200162000c1e565b8381111562000c48576000848401525b50505050565b613e598062000c5e6000396000f3fe608060405234801561001057600080fd5b506004361061030c5760003560e01c80637165485d1161019d578063ac00ff26116100e9578063ec38a862116100a2578063f017c92f1161007c578063f017c92f14610596578063fbfa77cf146105a9578063fcf2d0ad146105b1578063fe2508a6146105b95761030c565b8063ec38a86214610568578063ed882c2b1461057b578063efbb5cb01461058e5761030c565b8063ac00ff2614610517578063aced16611461052a578063b252720b14610532578063c1a3d44c1461053a578063c7b9d53014610542578063ce5494bb146105555761030c565b80638e6350e21161015657806395e80c501161013057806395e80c50146104f75780639ec5a894146104ff578063a6f19c8414610507578063aa5480cf1461050f5761030c565b80638e6350e2146104c957806391397ab4146104d1578063955383bd146104e45761030c565b80637165485d14610478578063748747e614610480578063750521f514610493578063780022a0146104a65780637fef901a146104b95780638cdfe166146104c15761030c565b80632e1a7d4d1161025c57806346c96aac116102155780635b9f0016116101ef5780635b9f00161461044d578063650d1880146104555780636718835f146104685780636a4874a1146104705761030c565b806346c96aac1461042a578063520009df146104325780635641ec03146104455761030c565b80632e1a7d4d146103e4578063327107f7146103f7578063372500ab146103ff57806339a172a814610407578063440368a31461041a5780634641257d146104225761030c565b806311bc8245116102c95780631fe4a686116102a35780631fe4a686146103b757806322f3e2d4146103bf57806325829410146103d457806328b7ccf7146103dc5761030c565b806311bc8245146103875780631d12f28b1461039a5780631f1fcd51146103af5761030c565b806301681a621461031157806303ee438c1461032657806306fdde03146103445780630ada4dab1461034c5780630d52333c1461035f5780630f969b8714610374575b600080fd5b61032461031f36600461372c565b6105cc565b005b61032e61076b565b60405161033b9190613a21565b60405180910390f35b61032e6107f9565b61032461035a3660046137f9565b61088f565b610367610a31565b60405161033b9190613968565b61032461038236600461391c565b610a49565b61032461039536600461372c565b610ad6565b6103a2610bd7565b60405161033b9190613cc0565b610367610bdd565b610367610bec565b6103c7610bfb565b60405161033b91906139e7565b61032e610c9d565b6103a2610cbc565b6103a26103f236600461391c565b610cc2565b610367610d1d565b610324610d2c565b61032461041536600461391c565b610e0f565b610324610e91565b6103246110b8565b610367611591565b61032461044036600461391c565b6115a9565b6103c76117eb565b6103a26117f4565b6103c761046336600461391c565b61187e565b6103c7611886565b61036761188f565b6103676118a7565b61032461048e36600461372c565b6118bf565b6103246104a1366004613831565b61196a565b6103a26104b436600461391c565b611a01565b6103a2611a04565b6103a2611a0a565b6103a2611a10565b6103246104df36600461391c565b611a15565b6103246104f236600461391c565b611a97565b6103a2611c3a565b610367611c40565b610367611c4f565b6103a2611c67565b6103246105253660046137f9565b611c6d565b610367611d59565b610367611d68565b6103a2611d7c565b61032461055036600461372c565b611dad565b61032461056336600461372c565b611e58565b61032461057636600461372c565b611fa3565b6103c761058936600461391c565b612136565b6103a26122b8565b6103246105a436600461391c565b6122d3565b610367612355565b610324612364565b6103246105c736600461391c565b612589565b6105d4612833565b6001600160a01b0316336001600160a01b03161461060d5760405162461bcd60e51b815260040161060490613bd7565b60405180910390fd5b6006546001600160a01b038281169116141561063b5760405162461bcd60e51b815260040161060490613a79565b6002546001600160a01b03828116911614156106695760405162461bcd60e51b815260040161060490613b7f565b60606106736128b0565b905060005b81518110156106ce5781818151811061068d57fe5b60200260200101516001600160a01b0316836001600160a01b031614156106c65760405162461bcd60e51b815260040161060490613c46565b600101610678565b506107676106da612833565b6040516370a0823160e01b81526001600160a01b038516906370a0823190610706903090600401613968565b60206040518083038186803b15801561071e57600080fd5b505afa158015610732573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107569190613934565b6001600160a01b03851691906128b5565b5050565b6000805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156107f15780601f106107c6576101008083540402835291602001916107f1565b820191906000526020600020905b8154815290600101906020018083116107d457829003601f168201915b505050505081565b600f8054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156108855780601f1061085a57610100808354040283529160200191610885565b820191906000526020600020905b81548152906001019060200180831161086857829003601f168201915b5050505050905090565b6003546001600160a01b03163314806108c057506108ab612833565b6001600160a01b0316336001600160a01b0316145b806109615750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561091457600080fd5b505afa158015610928573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094c9190613748565b6001600160a01b0316336001600160a01b0316145b80610a025750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b1580156109b557600080fd5b505afa1580156109c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ed9190613748565b6001600160a01b0316336001600160a01b0316145b610a1e5760405162461bcd60e51b815260040161060490613bd7565b600d805460ff1916911515919091179055565b73abc000d88f23bb45525e447528dbf656a9d55bf581565b6003546001600160a01b0316331480610a7a5750610a65612833565b6001600160a01b0316336001600160a01b0316145b610a965760405162461bcd60e51b815260040161060490613bd7565b600a8190556040517fa68ba126373d04c004c5748c300c9fca12bd444b3d4332e261f3bd2bac4a860090610acb908390613cc0565b60405180910390a150565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610b2457600080fd5b505afa158015610b38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5c9190613748565b6001600160a01b0316336001600160a01b03161480610b935750610b7e612833565b6001600160a01b0316336001600160a01b0316145b610baf5760405162461bcd60e51b815260040161060490613bd7565b600180546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b600a5481565b6006546001600160a01b031681565b6003546001600160a01b031681565b6002546040516339ebf82360e01b815260009182916001600160a01b03909116906339ebf82390610c30903090600401613968565b6101206040518083038186803b158015610c4957600080fd5b505afa158015610c5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c81919061389e565b604001511180610c9857506000610c966122b8565b115b905090565b604080518082019091526005815264302e342e3360d81b602082015290565b60085481565b6002546000906001600160a01b03163314610cef5760405162461bcd60e51b815260040161060490613b5f565b6000610cfa836128d4565b600654909350909150610d17906001600160a01b031633836128b5565b50919050565b6010546001600160a01b031681565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7a57600080fd5b505afa158015610d8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db29190613748565b6001600160a01b0316336001600160a01b03161480610de95750610dd4612833565b6001600160a01b0316336001600160a01b0316145b610e055760405162461bcd60e51b815260040161060490613bd7565b610e0d6129b8565b565b6003546001600160a01b0316331480610e405750610e2b612833565b6001600160a01b0316336001600160a01b0316145b610e5c5760405162461bcd60e51b815260040161060490613bd7565b60078190556040517fbb2c369a0355a34b02ab5fce0643150c87e1c8dfe7c918d465591879f57948b190610acb908390613cc0565b6005546001600160a01b0316331480610eb457506003546001600160a01b031633145b80610ed75750610ec2612833565b6001600160a01b0316336001600160a01b0316145b80610f785750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015610f2b57600080fd5b505afa158015610f3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f639190613748565b6001600160a01b0316336001600160a01b0316145b806110195750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610fcc57600080fd5b505afa158015610fe0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110049190613748565b6001600160a01b0316336001600160a01b0316145b6110355760405162461bcd60e51b815260040161060490613bd7565b6002546040805163bf3759b560e01b81529051610e0d926001600160a01b03169163bf3759b5916004808301926020929190829003018186803b15801561107b57600080fd5b505afa15801561108f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b39190613934565b612a37565b6005546001600160a01b03163314806110db57506003546001600160a01b031633145b806110fe57506110e9612833565b6001600160a01b0316336001600160a01b0316145b8061119f5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561115257600080fd5b505afa158015611166573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118a9190613748565b6001600160a01b0316336001600160a01b0316145b806112405750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b1580156111f357600080fd5b505afa158015611207573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122b9190613748565b6001600160a01b0316336001600160a01b0316145b61125c5760405162461bcd60e51b815260040161060490613bd7565b6000806000600260009054906101000a90046001600160a01b03166001600160a01b031663bf3759b56040518163ffffffff1660e01b815260040160206040518083038186803b1580156112af57600080fd5b505afa1580156112c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e79190613934565b600b5490915060009060ff1615611344576000611302612ac6565b90508281101561131d576113168382612b51565b9350611332565b828111156113325761132f8184612b51565b94505b61133c8385612b51565b915050611355565b61134d82612b9c565b919550935090505b6002546040516339ebf82360e01b81526000916001600160a01b0316906339ebf82390611386903090600401613968565b6101206040518083038186803b15801561139f57600080fd5b505afa1580156113b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d7919061389e565b60c001516002546040516328766ebf60e21b81529192506001600160a01b03169063a1d9bafc9061141090889088908790600401613d39565b602060405180830381600087803b15801561142a57600080fd5b505af115801561143e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114629190613934565b925061146d83612a37565b60015460ff16801561148e575060015461010090046001600160a01b031615155b156115405760015460405163c70fa00b60e01b81526101009091046001600160a01b03169063c70fa00b906114cf9088908890879089908890600401613d6a565b60206040518083038186803b1580156114e757600080fd5b505afa1580156114fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151f9190613815565b61153b5760405162461bcd60e51b815260040161060490613acf565b61154d565b6001805460ff1916811790555b7f4c0f499ffe6befa0ca7c826b0916cf87bea98de658013e76938489368d60d509858584866040516115829493929190613d4f565b60405180910390a15050505050565b736346282db8323a54e840c6c772b4399c9c655c0d81565b6003546001600160a01b03163314806115da57506115c5612833565b6001600160a01b0316336001600160a01b0316145b8061167b5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561162e57600080fd5b505afa158015611642573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116669190613748565b6001600160a01b0316336001600160a01b0316145b8061171c5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b1580156116cf57600080fd5b505afa1580156116e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117079190613748565b6001600160a01b0316336001600160a01b0316145b6117385760405162461bcd60e51b815260040161060490613bd7565b8061176857601080546001600160a01b0319167382af49447d8a07e3bd95bd0d56f35241523fbab11790556117e8565b806001141561179c57601080546001600160a01b031916732f2a2543b76a4166549f7aab2e75bef0aefc5b0f1790556117e8565b80600214156117d057601080546001600160a01b03191673fd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb91790556117e8565b60405162461bcd60e51b815260040161060490613af5565b50565b600b5460ff1681565b6040516370a0823160e01b815260009073555766f3da968ecbefa690ffd49a2ac02f47aa5f906370a082319061182e903090600401613968565b60206040518083038186803b15801561184657600080fd5b505afa15801561185a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c989190613934565b60005b919050565b60015460ff1681565b7311cdb42b0eb46d95f990bedd4695a6e3fa03497881565b73960ea3e3c7fb317332d990873d354e18d764559081565b6003546001600160a01b03163314806118f057506118db612833565b6001600160a01b0316336001600160a01b0316145b61190c5760405162461bcd60e51b815260040161060490613bd7565b6001600160a01b03811661191f57600080fd5b600580546001600160a01b0319166001600160a01b0383161790556040517f2f202ddb4a2e345f6323ed90f8fc8559d770a7abbbeee84dde8aca3351fe715490610acb908390613968565b6003546001600160a01b031633148061199b5750611986612833565b6001600160a01b0316336001600160a01b0316145b6119b75760405162461bcd60e51b815260040161060490613bd7565b6119c36000838361364d565b507f300e67d5a415b6d015a471d9c7b95dd58f3e8290af965e84e0f845de2996dda682826040516119f59291906139f2565b60405180910390a15050565b90565b600c5481565b60095481565b600090565b6003546001600160a01b0316331480611a465750611a31612833565b6001600160a01b0316336001600160a01b0316145b611a625760405162461bcd60e51b815260040161060490613bd7565b60098190556040517fd94596337df4c2f0f44d30a7fc5db1c7bb60d9aca4185ed77c6fd96eb45ec29890610acb908390613cc0565b6003546001600160a01b0316331480611ac85750611ab3612833565b6001600160a01b0316336001600160a01b0316145b80611b695750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015611b1c57600080fd5b505afa158015611b30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b549190613748565b6001600160a01b0316336001600160a01b0316145b80611c0a5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015611bbd57600080fd5b505afa158015611bd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bf59190613748565b6001600160a01b0316336001600160a01b0316145b611c265760405162461bcd60e51b815260040161060490613bd7565b612710811115611c3557600080fd5b600c55565b60075481565b6004546001600160a01b031681565b73555766f3da968ecbefa690ffd49a2ac02f47aa5f81565b600e5481565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015611cbb57600080fd5b505afa158015611ccf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf39190613748565b6001600160a01b0316336001600160a01b03161480611d2a5750611d15612833565b6001600160a01b0316336001600160a01b0316145b611d465760405162461bcd60e51b815260040161060490613bd7565b6001805460ff1916911515919091179055565b6005546001600160a01b031681565b60015461010090046001600160a01b031681565b6006546040516370a0823160e01b81526000916001600160a01b0316906370a082319061182e903090600401613968565b6003546001600160a01b0316331480611dde5750611dc9612833565b6001600160a01b0316336001600160a01b0316145b611dfa5760405162461bcd60e51b815260040161060490613bd7565b6001600160a01b038116611e0d57600080fd5b600380546001600160a01b0319166001600160a01b0383161790556040517f352ececae6d7d1e6d26bcf2c549dfd55be1637e9b22dc0cf3b71ddb36097a6b490610acb908390613968565b6002546001600160a01b03163314611e6f57600080fd5b6002546040805163fbfa77cf60e01b815290516001600160a01b039283169284169163fbfa77cf916004808301926020929190829003018186803b158015611eb657600080fd5b505afa158015611eca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eee9190613748565b6001600160a01b031614611f0157600080fd5b611f0a81613124565b6006546040516370a0823160e01b81526117e89183916001600160a01b03909116906370a0823190611f40903090600401613968565b60206040518083038186803b158015611f5857600080fd5b505afa158015611f6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f909190613934565b6006546001600160a01b031691906128b5565b6003546001600160a01b03163314611fcd5760405162461bcd60e51b815260040161060490613a54565b6001600160a01b038116611fe057600080fd5b6002546004805460405163095ea7b360e01b81526001600160a01b039384169363095ea7b393612017939091169160009101613996565b602060405180830381600087803b15801561203157600080fd5b505af1158015612045573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120699190613815565b50600480546001600160a01b0319166001600160a01b038381169190911780835560025460405163095ea7b360e01b81529083169363095ea7b3936120b49316916000199101613996565b602060405180830381600087803b1580156120ce57600080fd5b505af11580156120e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121069190613815565b507fafbb66abf8f3b719799940473a4052a3717cdd8e40fb6c8a3faadab316b1a06981604051610acb9190613968565b6000612140610bfb565b61214c57506000611881565b6121546136cb565b6002546040516339ebf82360e01b81526001600160a01b03909116906339ebf82390612184903090600401613968565b6101206040518083038186803b15801561219d57600080fd5b505afa1580156121b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d5919061389e565b90506008546121f18260a0015142612b5190919063ffffffff16565b1115612201576001915050611881565b600e54600260009054906101000a90046001600160a01b03166001600160a01b031663112c1f9b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561225257600080fd5b505afa158015612266573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061228a9190613934565b111561229a576001915050611881565b600d5460ff16156122af576001915050611881565b50600092915050565b6000610c986122c56117f4565b6122cd611d7c565b9061316d565b6003546001600160a01b031633148061230457506122ef612833565b6001600160a01b0316336001600160a01b0316145b6123205760405162461bcd60e51b815260040161060490613bd7565b60088190556040517f5430e11864ad7aa9775b07d12657fe52df9aa2ba734355bd8ef8747be2c800c590610acb908390613cc0565b6002546001600160a01b031681565b6003546001600160a01b03163314806123955750612380612833565b6001600160a01b0316336001600160a01b0316145b806124365750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b1580156123e957600080fd5b505afa1580156123fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124219190613748565b6001600160a01b0316336001600160a01b0316145b806124d75750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561248a57600080fd5b505afa15801561249e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124c29190613748565b6001600160a01b0316336001600160a01b0316145b6124f35760405162461bcd60e51b815260040161060490613bd7565b600b805460ff191660011790556002546040805163507257cd60e11b815290516001600160a01b039092169163a0e4af9a9160048082019260009290919082900301818387803b15801561254657600080fd5b505af115801561255a573d6000803e3d6000fd5b50506040517f97e963041e952738788b9d4871d854d282065b8f90a464928d6528f2e9a4fd0b925060009150a1565b6003546001600160a01b03163314806125ba57506125a5612833565b6001600160a01b0316336001600160a01b0316145b8061265b5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561260e57600080fd5b505afa158015612622573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126469190613748565b6001600160a01b0316336001600160a01b0316145b806126fc5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b1580156126af57600080fd5b505afa1580156126c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126e79190613748565b6001600160a01b0316336001600160a01b0316145b6127185760405162461bcd60e51b815260040161060490613bd7565b600e55565b8015806127a55750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90612753903090869060040161397c565b60206040518083038186803b15801561276b57600080fd5b505afa15801561277f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127a39190613934565b155b6127c15760405162461bcd60e51b815260040161060490613c6a565b6128178363095ea7b360e01b84846040516024016127e0929190613996565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613192565b505050565b606061282b8484600085613221565b949350505050565b60025460408051635aa6e67560e01b815290516000926001600160a01b031691635aa6e675916004808301926020929190829003018186803b15801561287857600080fd5b505afa15801561288c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c989190613748565b606090565b6128178363a9059cbb60e01b84846040516024016127e0929190613996565b60008060006128e1611d7c565b9050808411156129a45760006128f56117f4565b905080156129795773555766f3da968ecbefa690ffd49a2ac02f47aa5f632e1a7d4d61292a836129258987612b51565b6132e5565b6040518263ffffffff1660e01b81526004016129469190613cc0565b600060405180830381600087803b15801561296057600080fd5b505af1158015612974573d6000803e3d6000fd5b505050505b6000612983611d7c565b905061298f86826132e5565b945061299b8686612b51565b935050506129b1565b83600092509250506129b3565b505b915091565b6040516335313c2160e11b815273abc000d88f23bb45525e447528dbf656a9d55bf590636a62784290612a039073555766f3da968ecbefa690ffd49a2ac02f47aa5f90600401613968565b600060405180830381600087803b158015612a1d57600080fd5b505af1158015612a31573d6000803e3d6000fd5b50505050565b600b5460ff1615612a47576117e8565b6000612a51611d7c565b905080156107675760405163b6b55f2560e01b815273555766f3da968ecbefa690ffd49a2ac02f47aa5f9063b6b55f2590612a90908490600401613cc0565b600060405180830381600087803b158015612aaa57600080fd5b505af1158015612abe573d6000803e3d6000fd5b505050505050565b600080612ad16117f4565b90508015612b4357604051632e1a7d4d60e01b815273555766f3da968ecbefa690ffd49a2ac02f47aa5f90632e1a7d4d90612b10908490600401613cc0565b600060405180830381600087803b158015612b2a57600080fd5b505af1158015612b3e573d6000803e3d6000fd5b505050505b612b4b611d7c565b91505090565b6000612b9383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506132fb565b90505b92915050565b6000806000612ba96129b8565b6040516370a0823160e01b81526000907311cdb42b0eb46d95f990bedd4695a6e3fa034978906370a0823190612be3903090600401613968565b60206040518083038186803b158015612bfb57600080fd5b505afa158015612c0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c339190613934565b90508015612d36576000612c5e612710612c58600c548561332790919063ffffffff16565b90613361565b600c5490915015612c9c57612c9c7311cdb42b0eb46d95f990bedd4695a6e3fa034978736346282db8323a54e840c6c772b4399c9c655c0d836128b5565b6040516370a0823160e01b81527311cdb42b0eb46d95f990bedd4695a6e3fa034978906370a0823190612cd3903090600401613968565b60206040518083038186803b158015612ceb57600080fd5b505afa158015612cff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d239190613934565b91508115612d3457612d34826133a3565b505b6040516370a0823160e01b81526000907382af49447d8a07e3bd95bd0d56f35241523fbab1906370a0823190612d70903090600401613968565b60206040518083038186803b158015612d8857600080fd5b505afa158015612d9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc09190613934565b6040516370a0823160e01b8152909150600090732f2a2543b76a4166549f7aab2e75bef0aefc5b0f906370a0823190612dfd903090600401613968565b60206040518083038186803b158015612e1557600080fd5b505afa158015612e29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e4d9190613934565b6040516370a0823160e01b815290915060009073fd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9906370a0823190612e8a903090600401613968565b60206040518083038186803b158015612ea257600080fd5b505afa158015612eb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eda9190613934565b90506000831180612eeb5750600082115b80612ef65750600081115b15612f805760408051606081018252828152602081018490528082018590529051634515cef360e01b815273960ea3e3c7fb317332d990873d354e18d764559091634515cef391612f4d91906000906004016139af565b600060405180830381600087803b158015612f6757600080fd5b505af1158015612f7b573d6000803e3d6000fd5b505050505b6000612f8a6117f4565b9050881561302557801561300b5773555766f3da968ecbefa690ffd49a2ac02f47aa5f632e1a7d4d612fbc838c6132e5565b6040518263ffffffff1660e01b8152600401612fd89190613cc0565b600060405180830381600087803b158015612ff257600080fd5b505af1158015613006573d6000803e3d6000fd5b505050505b6000613015611d7c565b90506130218a826132e5565b9650505b600061302f6122b8565b6002546040516339ebf82360e01b81529192506000916001600160a01b03909116906339ebf82390613065903090600401613968565b6101206040518083038186803b15801561307e57600080fd5b505afa158015613092573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b6919061389e565b60c001519050808211156130fd576130ce8282612b51565b995060006130da611d7c565b9050806130e78c8b61316d565b11156130f7576130f5612ac6565b505b5061310a565b6131078183612b51565b98505b5050600d805460ff19169055509597949650929450505050565b600061312e6117f4565b9050801561076757604051632e1a7d4d60e01b815273555766f3da968ecbefa690ffd49a2ac02f47aa5f90632e1a7d4d90612a90908490600401613cc0565b600082820183811015612b935760405162461bcd60e51b815260040161060490613a98565b60606131e7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661281c9092919063ffffffff16565b80519091501561281757808060200190518101906132059190613815565b6128175760405162461bcd60e51b815260040161060490613bfc565b606061322c856135dd565b6132485760405162461bcd60e51b815260040161060490613ba0565b60006060866001600160a01b03168587604051613265919061394c565b60006040518083038185875af1925050503d80600081146132a2576040519150601f19603f3d011682016040523d82523d6000602084013e6132a7565b606091505b509150915081156132bb57915061282b9050565b8051156132cb5780518082602001fd5b8360405162461bcd60e51b81526004016106049190613a21565b60008183106132f45781612b93565b5090919050565b6000818484111561331f5760405162461bcd60e51b81526004016106049190613a21565b505050900390565b60008261333657506000612b96565b8282028284828161334357fe5b0414612b935760405162461bcd60e51b815260040161060490613b1e565b6000612b9383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613616565b6010546060906001600160a01b03167382af49447d8a07e3bd95bd0d56f35241523fbab114156134765760408051600280825260608201835290916020830190803683370190505090507311cdb42b0eb46d95f990bedd4695a6e3fa0349788160008151811061340f57fe5b60200260200101906001600160a01b031690816001600160a01b0316815250507382af49447d8a07e3bd95bd0d56f35241523fbab18160018151811061345157fe5b60200260200101906001600160a01b031690816001600160a01b031681525050613547565b6040805160038082526080820190925290602082016060803683370190505090507311cdb42b0eb46d95f990bedd4695a6e3fa034978816000815181106134b957fe5b60200260200101906001600160a01b031690816001600160a01b0316815250507382af49447d8a07e3bd95bd0d56f35241523fbab1816001815181106134fb57fe5b6001600160a01b03928316602091820292909201015260105482519116908290600290811061352657fe5b60200260200101906001600160a01b031690816001600160a01b0316815250505b6040516338ed173960e01b8152731b02da8cb0d097eb8d57a175b88c7d8b47997506906338ed173990613587908590600090869030904290600401613cc9565b600060405180830381600087803b1580156135a157600080fd5b505af11580156135b5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128179190810190613764565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061282b575050151592915050565b600081836136375760405162461bcd60e51b81526004016106049190613a21565b50600083858161364357fe5b0495945050505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061368e5782800160ff198235161785556136bb565b828001600101855582156136bb579182015b828111156136bb5782358255916020019190600101906136a0565b506136c7929150613717565b5090565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b5b808211156136c75760008155600101613718565b60006020828403121561373d578081fd5b8135612b9381613e00565b600060208284031215613759578081fd5b8151612b9381613e00565b60006020808385031215613776578182fd5b825167ffffffffffffffff81111561378c578283fd5b8301601f8101851361379c578283fd5b80516137af6137aa82613db4565b613d8d565b81815283810190838501858402850186018910156137cb578687fd5b8694505b838510156137ed5780518352600194909401939185019185016137cf565b50979650505050505050565b60006020828403121561380a578081fd5b8135612b9381613e15565b600060208284031215613826578081fd5b8151612b9381613e15565b60008060208385031215613843578081fd5b823567ffffffffffffffff8082111561385a578283fd5b818501915085601f83011261386d578283fd5b81358181111561387b578384fd5b86602082850101111561388c578384fd5b60209290920196919550909350505050565b60006101208083850312156138b1578182fd5b6138ba81613d8d565b9050825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b60006020828403121561392d578081fd5b5035919050565b600060208284031215613945578081fd5b5051919050565b6000825161395e818460208701613dd4565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b60808101818460005b60038110156139d75781518352602092830192909101906001016139b8565b5050508260608301529392505050565b901515815260200190565b60006020825282602083015282846040840137818301604090810191909152601f909201601f19160101919050565b6000602082528251806020840152613a40816040850160208701613dd4565b601f01601f19169190910160400192915050565b6020808252600b908201526a085cdd1c985d1959da5cdd60aa1b604082015260600190565b602080825260059082015264085dd85b9d60da1b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252600c908201526b216865616c7468636865636b60a01b604082015260600190565b6020808252600f908201526e34b731b7b93932b1ba103a37b5b2b760891b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b602080825260069082015265085d985d5b1d60d21b604082015260600190565b6020808252600790820152662173686172657360c81b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252600b908201526a08585d5d1a1bdc9a5e995960aa1b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252600a9082015269085c1c9bdd1958dd195960b21b604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b90815260200190565b600060a082018783526020878185015260a0604085015281875180845260c0860191508289019350845b81811015613d185784516001600160a01b031683529383019391830191600101613cf3565b50506001600160a01b03969096166060850152505050608001529392505050565b9283526020830191909152604082015260600190565b93845260208401929092526040830152606082015260800190565b948552602085019390935260408401919091526060830152608082015260a00190565b60405181810167ffffffffffffffff81118282101715613dac57600080fd5b604052919050565b600067ffffffffffffffff821115613dca578081fd5b5060209081020190565b60005b83811015613def578181015183820152602001613dd7565b83811115612a315750506000910152565b6001600160a01b03811681146117e857600080fd5b80151581146117e857600080fdfea26469706673582212201cd35edb4e263f157b70f448481f8edf282ed18e605a6f9aa944983d6a61b5b764736f6c634300060c0033000000000000000000000000239e14a19dff93a17339dcc444f74406c17f8e67000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000165374726174656779437572766554726963727970746f00000000000000000000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000239e14a19dff93a17339dcc444f74406c17f8e67000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000165374726174656779437572766554726963727970746f00000000000000000000
-----Decoded View---------------
Arg [0] : _vault (address): 0x239e14a19dff93a17339dcc444f74406c17f8e67
Arg [1] : _name (string): StrategyCurveTricrypto
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000239e14a19dff93a17339dcc444f74406c17f8e67
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000016
Arg [3] : 5374726174656779437572766554726963727970746f00000000000000000000
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.