Contract Overview
My Name Tag:
Not Available
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
Contract Name:
StrategyCurveTwoPool
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 "SafeERC20.sol"; import "SafeMath.sol"; import "Address.sol"; import "Math.sol"; import { ICurveGauge, ICurveGaugeFactory, ICurvePool } from "ICurveTwoPool.sol"; import { ISwapRouter } from "ISwapRouter.sol"; // Uni V3 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 (`2CRV` LP tokens, `crv3crypto` LP tokens, etc.). // Curve contracts ICurveGauge internal constant gauge = ICurveGauge(0xCE5F24B7A95e9cBa7df4B54E911B4A3Dc8CDAf6f); ICurveGaugeFactory internal constant gaugeFactory = ICurveGaugeFactory(0xabC000d88f23Bb45525E447528DBF656A9D55bf5); ICurvePool internal constant pool = ICurvePool(0x7f90122BF0700F9E7e1F688fe926940E8839F353); IERC20 internal constant crv = IERC20(0x11cDb42B0EB46D95f990BeDD4695A6e3fA034978); // keepCRV uint256 public keepCRV; // the percentage of CRV we re-lock for boost (in basis points) uint256 public constant feeDenominator = 10_000; // this means all of our fee values are in bips address public constant voter = 0x6346282DB8323A54E840c6C772B4399C9c655C0d; // Strategists multi-sig // Uniswap V3 router ISwapRouter internal constant router = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564); // WETH used in multi hop swaps address internal constant wethAddress = 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1; 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 /* ========== CONSTRUCTOR ========== */ constructor(address _vaultAddress) public BaseStrategy(_vaultAddress) { // Our standard approvals. want = Curve LP token want.approve(address(gauge), type(uint256).max); crv.approve(address(router), type(uint256).max); maxReportDelay = 2 days; // 2 days in seconds healthCheck = 0x32059ccE723b4DD15dD5cb2a5187f814e6c470bC; } /* ========== VIEWS ========== */ 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); } } 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. Note that this function does not claim // any pending rewards. 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. // Credit threshold is in want token, and will trigger a harvest if credit is large enough. function setCreditThreshold(uint256 _creditThreshold) external onlyVaultManagers { creditThreshold = _creditThreshold; } // This allows us to manually harvest with our keeper as needed function setForceHarvestTriggerOnce(bool _forceHarvestTriggerOnce) external onlyVaultManagers { forceHarvestTriggerOnce = _forceHarvestTriggerOnce; } // Set the amount of CRV to be locked in Yearn's veCRV voter from each harvest. Default is 10%. function setKeepCRV(uint256 _keepCRV) external onlyAuthorized { require(_keepCRV <= 10_000); // dev: cannot be over 100% keepCRV = _keepCRV; } /* ========== KEEP3RS ========== */ /// @param callCostInWei Cost of the contract call to harvest(). Used to determine if the profit (if any) is /// sufficiently large to justify the call to harvest() function harvestTrigger(uint256 callCostInWei) public view override returns (bool) { // Should not trigger if strategy is not active (no assets and no debtRatio). This means we don't need to adjust keeper job. if (!isActive()) { return false; } StrategyParams memory params = vault.strategies(address(this)); // 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) {} } contract StrategyCurveTwoPool is StrategyCurveBase { /* ========== STATE VARIABLES ========== */ // `targetTokenAddress` is the token we buy with CRV rewards and the token we then // deposit into the curve pool -- USDT or USDC address public targetTokenAddress; IERC20 internal constant usdt = IERC20(0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9); IERC20 internal constant usdc = IERC20(0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8); // Uniswap V3 pool fees uint24 public crvToWethSwapFee = 3000; uint24 public wethToTargetSwapFee = 500; uint24 internal constant maxFee = 10000; string internal stratName; // set our strategy name here /* ============= CONSTRUCTOR =========== */ constructor(address _vaultAddress, string memory _stratName) public StrategyCurveBase(_vaultAddress) { // Set our strategy's name stratName = _stratName; // Required strategic-specific approvals usdt.approve(address(pool), type(uint256).max); usdc.approve(address(pool), type(uint256).max); // Start off with USDC targetTokenAddress = address(usdc); } /* ========== 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) for our `targetToken` (USDC or USDT) if (crvBalance > 0) { if (keepCRV > 0) { // keep some of our CRV to increase our boost uint256 sendToVoter = crvBalance.mul(keepCRV).div( feeDenominator ); crv.safeTransfer(voter, sendToVoter); crvBalance = crvBalance.sub(sendToVoter); } // sell the rest of our CRV _sell(crvBalance); } // Check balance of tokens. We do this outside the prev. if statement in // case there are donations to the strategy. uint256 usdtBalance = usdt.balanceOf(address(this)); uint256 usdcBalance = usdc.balanceOf(address(this)); if (usdtBalance > 0 || usdcBalance > 0) { pool.add_liquidity([usdcBalance, usdtBalance], 0); } // debtOustanding will only be > 0 in the event of revoking or if we need to rebalance from a withdrawal or lowering the debtRatio if (_debtOutstanding > 0) { uint256 stakedBal = stakedBalance(); // Balance of gauge tokens by depositing curve LP tokens into the curve gauge if (stakedBal > 0) { // don't bother withdrawing if we don't have staked funds gauge.withdraw(Math.min(stakedBal, _debtOutstanding)); } uint256 _withdrawnBal = balanceOfWant(); // Balance of curve LP token _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, we have a profit 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 have a loss else { _loss = debt.sub(assets); } // we're done harvesting, so reset our trigger if we used it forceHarvestTriggerOnce = false; } // Sell our CRV in Uniswap V3 for our `targetToken`, USDT or USDC function _sell(uint256 _amount) internal { // gets multi-hop path for uniswap v3 swaps bytes memory path = abi.encodePacked( address(crv), crvToWethSwapFee, wethAddress, wethToTargetSwapFee, targetTokenAddress ); router.exactInput( ISwapRouter.ExactInputParams( path, // multi-hop path address(this), now, _amount, 0 // amountOutMinimum ) ); } /* ========== VIEWS ========== */ function name() external view override returns (string memory) { return stratName; } /* ========== 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 USDC, but can be set to USDT as needed by strategist or governance. function setTargetToken(uint256 _target) external onlyVaultManagers { require(_target < 2); // dev: not a valid index => use 0: USDT 1: USDC if (_target == 1) { targetTokenAddress = address(usdc); } else { targetTokenAddress = address(usdt); } } function setSwapFees(uint24 _crvToWethSwapFee, uint24 _wethToTargetSwapFee) external onlyVaultManagers { require(_crvToWethSwapFee <= maxFee); // dev: fee is too high require(_wethToTargetSwapFee <= maxFee); // dev: fee is too high // Likely to be run when/if we change the target token crvToWethSwapFee = _crvToWethSwapFee; wethToTargetSwapFee = _wethToTargetSwapFee; } }
// 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 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; /** * @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; import { IERC20 } from "SafeERC20.sol"; interface ICurveGauge is IERC20 { /// @notice Deposit `_value` LP tokens for `msg.sender` without claiming pending rewards (if any) /// @param _value Number of LP tokens to deposit function deposit(uint256 _value) external; /// @notice Withdraw `_value` LP tokens without claiming pending rewards (if any) /// @param _value Number of LP tokens to withdraw function withdraw(uint256 _value) external; /// @notice Get the number of claimable tokens per user /// @dev This function should be manually changed to "view" in the ABI /// @return uint256 number of claimable tokens per user function claimable_tokens(address addr) external returns (uint256); function factory() external view returns (address); function inflation_rate(uint256) external view returns (uint256); function reward_count() external view returns (uint256); } interface ICurveGaugeFactory { function mint(address _gauge) external; } interface ICurvePool is IERC20 { // 2CRV pool relies on 2 tokens. Vyper does not yet support dynamic arrays so that we need to // hard-code '2' for all the relevant functions in this interface. /// @notice Deposit coins into the pool /// @param _amounts List of amounts of coins to deposit /// @param _min_mint_amount Minimum amount of LP tokens to mint from the deposit /// @return Amount of LP tokens received by depositing function add_liquidity( uint256[2] calldata _amounts, uint256 _min_mint_amount ) external returns (uint256); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.6.12; pragma experimental ABIEncoderV2; /// @title Router token swapping functionality /// @notice Functions for swapping tokens via Uniswap V3 using their first implementation interface ISwapRouter { struct ExactInputParams { bytes path; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; } /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata /// @return amountOut The amount of the received token function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); } /// @title Router token swapping functionality /// @notice Functions for swapping tokens via Uniswap V3 using their second implementation interface ISwapRouterV2 { struct ExactInputParams { bytes path; address recipient; uint256 amountIn; uint256 amountOutMinimum; } /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata /// @return amountOut The amount of the received token function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); }
// 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); event SetHealthCheck(address); event SetDoHealthCheck(bool); // 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 { emit SetHealthCheck(_healthCheck); healthCheck = _healthCheck; } function setDoHealthCheck(bool _doHealthCheck) external onlyVaultManagers { emit SetDoHealthCheck(_doHealthCheck); 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 { emit SetDoHealthCheck(true); 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": { "StrategyCurveTwoPool.sol": {} }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
[{"inputs":[{"internalType":"address","name":"_vaultAddress","type":"address"},{"internalType":"string","name":"_stratName","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":"bool","name":"","type":"bool"}],"name":"SetDoHealthCheck","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"","type":"address"}],"name":"SetHealthCheck","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":"crvToWethSwapFee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"debtThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegatedAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"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":"feeDenominator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"callCostInWei","type":"uint256"}],"name":"harvestTrigger","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"healthCheck","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"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":"_profitFactor","type":"uint256"}],"name":"setProfitFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewards","type":"address"}],"name":"setRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategist","type":"address"}],"name":"setStrategist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"_crvToWethSwapFee","type":"uint24"},{"internalType":"uint24","name":"_wethToTargetSwapFee","type":"uint24"}],"name":"setSwapFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_target","type":"uint256"}],"name":"setTargetToken","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":"targetTokenAddress","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":[],"name":"wethToTargetSwapFee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"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
6080604052600f805462ffffff60a01b191661017760a31b1762ffffff60b81b1916607d60ba1b1790553480156200003657600080fd5b50604051620045e0380380620045e0833981016040819052620000599162000909565b8180620000698133808062000377565b5060065460405163095ea7b360e01b81526001600160a01b039091169063095ea7b390620000b49073ce5f24b7a95e9cba7df4b54e911b4a3dc8cdaf6f906000199060040162000a35565b602060405180830381600087803b158015620000cf57600080fd5b505af1158015620000e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010a9190620009c2565b5060405163095ea7b360e01b81527311cdb42b0eb46d95f990bedd4695a6e3fa0349789063095ea7b3906200015c9073e592427a0aece92de3edee1f18e0157c05861564906000199060040162000a35565b602060405180830381600087803b1580156200017757600080fd5b505af11580156200018c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b29190620009c2565b50506202a30060085560018054610100600160a81b0319167432059cce723b4dd15dd5cb2a5187f814e6c470bc001790558051620001f89060109060208401906200082a565b5060405163095ea7b360e01b815273fd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb99063095ea7b3906200024a90737f90122bf0700f9e7e1f688fe926940e8839f353906000199060040162000a35565b602060405180830381600087803b1580156200026557600080fd5b505af11580156200027a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002a09190620009c2565b5060405163095ea7b360e01b815273ff970a61a04b1ca14834a43f5de4533ebddb5cc89063095ea7b390620002f290737f90122bf0700f9e7e1f688fe926940e8839f353906000199060040162000a35565b602060405180830381600087803b1580156200030d57600080fd5b505af115801562000322573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003489190620009c2565b5050600f80546001600160a01b03191673ff970a61a04b1ca14834a43f5de4533ebddb5cc81790555062000bcb565b6006546001600160a01b031615620003ac5760405162461bcd60e51b8152600401620003a39062000a83565b60405180910390fd5b600280546001600160a01b0319166001600160a01b03868116919091179182905560408051637e062a3560e11b81529051929091169163fc0c546a91600480820192602092909190829003018186803b1580156200040957600080fd5b505afa1580156200041e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004449190620008e4565b600680546001600160a01b0319166001600160a01b0392831617908190556200047e9116856000196200055b602090811b6200252a17901c565b600380546001600160a01b038086166001600160a01b03199283161790925560048054858416908316178082556005805486861694169390931790925560006007819055620151806008556064600955600a5560025460405163095ea7b360e01b81529084169363095ea7b393620004fe93911691600019910162000a35565b602060405180830381600087803b1580156200051957600080fd5b505af11580156200052e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005549190620009c2565b5050505050565b801580620005ea5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e9062000594903090869060040162000a1b565b60206040518083038186803b158015620005ad57600080fd5b505afa158015620005c2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005e89190620009e4565b155b620006095760405162461bcd60e51b8152600401620003a39062000b3b565b620006648363095ea7b360e01b84846040516024016200062b92919062000a35565b60408051808303601f190181529190526020810180516001600160e01b0319939093166001600160e01b03938416179052906200066916565b505050565b6060620006c5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200070560201b62002629179092919060201c565b805190915015620006645780806020019051810190620006e69190620009c2565b620006645760405162461bcd60e51b8152600401620003a39062000af1565b60606200071684846000856200071e565b949350505050565b60606200072b85620007f0565b6200074a5760405162461bcd60e51b8152600401620003a39062000aba565b60006060866001600160a01b03168587604051620007699190620009fd565b60006040518083038185875af1925050503d8060008114620007a8576040519150601f19603f3d011682016040523d82523d6000602084013e620007ad565b606091505b50915091508115620007c3579150620007169050565b805115620007d45780518082602001fd5b8360405162461bcd60e51b8152600401620003a3919062000a4e565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159062000716575050151592915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200086d57805160ff19168380011785556200089d565b828001600101855582156200089d579182015b828111156200089d57825182559160200191906001019062000880565b50620008ab929150620008af565b5090565b5b80821115620008ab5760008155600101620008b0565b80516001600160a01b0381168114620008de57600080fd5b92915050565b600060208284031215620008f6578081fd5b620009028383620008c6565b9392505050565b600080604083850312156200091c578081fd5b620009288484620008c6565b60208401519092506001600160401b038082111562000945578283fd5b818501915085601f83011262000959578283fd5b81518181111562000968578384fd5b604051601f8201601f19168101602001838111828210171562000989578586fd5b604052818152838201602001881015620009a1578485fd5b620009b482602083016020870162000b98565b809450505050509250929050565b600060208284031215620009d4578081fd5b8151801515811462000902578182fd5b600060208284031215620009f6578081fd5b5051919050565b6000825162000a1181846020870162000b98565b9190910192915050565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b600060208252825180602084015262000a6f81604085016020870162000b98565b601f01601f19169190910160400192915050565b6020808252601c908201527f537472617465677920616c726561647920696e697469616c697a656400000000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000606082015260800190565b60005b8381101562000bb557818101518382015260200162000b9b565b8381111562000bc5576000848401525b50505050565b613a058062000bdb6000396000f3fe608060405234801561001057600080fd5b506004361061030c5760003560e01c8063748747e61161019d578063ae49945d116100e9578063ec38a862116100a2578063f017c92f1161007c578063f017c92f146105a9578063fbfa77cf146105bc578063fcf2d0ad146105c4578063fe2508a6146105cc5761030c565b8063ec38a8621461057b578063ed882c2b1461058e578063efbb5cb0146105a15761030c565b8063ae49945d14610535578063b252720b1461053d578063c1a3d44c14610545578063c7b9d5301461054d578063ce5494bb14610560578063e41e9d22146105735761030c565b806391397ab4116101565780639ec5a894116101305780639ec5a8941461050a578063aa5480cf14610512578063ac00ff261461051a578063aced16611461052d5761030c565b806391397ab4146104dc578063955383bd146104ef57806395e80c50146105025761030c565b8063748747e614610490578063750521f5146104a3578063780022a0146104b65780637fef901a146104c45780638cdfe166146104cc5780638e6350e2146104d45761030c565b8063258294101161025c5780634641257d116102155780635641ec03116101ef5780635641ec03146104655780635b9f00161461046d578063650d1880146104755780636718835f146104885761030c565b80634641257d1461044257806346c96aac1461044a5780634b9765da146104525761030c565b806325829410146103fc57806328b7ccf7146104045780632e1a7d4d1461040c578063372500ab1461041f57806339a172a814610427578063440368a31461043a5761030c565b806311bc8245116102c95780631f1fcd51116102a35780631f1fcd51146103b55780631fe4a686146103ca5780632083e9c8146103d257806322f3e2d4146103e75761030c565b806311bc824514610385578063180b0d7e146103985780631d12f28b146103ad5761030c565b806301681a621461031157806303ee438c1461032657806306fdde03146103445780630ada4dab1461034c5780630f969b871461035f578063101e4f9e14610372575b600080fd5b61032461031f36600461332c565b6105df565b005b61032e61077e565b60405161033b919061363e565b60405180910390f35b61032e61080c565b61032461035a366004613364565b6108a2565b61032461036d3660046134bb565b61098e565b610324610380366004613487565b610a1b565b61032461039336600461332c565b610b54565b6103a0610c8c565b60405161033b91906138fc565b6103a0610c92565b6103bd610c98565b60405161033b9190613585565b6103bd610ca7565b6103da610cb6565b60405161033b91906138ec565b6103ef610cc8565b60405161033b9190613604565b61032e610d6a565b6103a0610d89565b6103a061041a3660046134bb565b610d8f565b610324610dea565b6103246104353660046134bb565b610ecd565b610324610f4f565b610324611176565b6103bd611687565b6103246104603660046134bb565b61169f565b6103ef6117e3565b6103a06117ec565b6103ef6104833660046134bb565b611876565b6103ef61187e565b61032461049e36600461332c565b611887565b6103246104b136600461339c565b611932565b6103a06104833660046134bb565b6103a06119c9565b6103a06119cf565b6103a06119d5565b6103246104ea3660046134bb565b6119da565b6103246104fd3660046134bb565b611a5c565b6103a0611abd565b6103bd611ac3565b6103a0611ad2565b610324610528366004613364565b611ad8565b6103bd611bfb565b6103bd611c0a565b6103bd611c19565b6103a0611c2d565b61032461055b36600461332c565b611c5e565b61032461056e36600461332c565b611d09565b6103da611e54565b61032461058936600461332c565b611e66565b6103ef61059c3660046134bb565b611ff9565b6103a061217b565b6103246105b73660046134bb565b612196565b6103bd612218565b610324612227565b6103246105da3660046134bb565b61244c565b6105e7612640565b6001600160a01b0316336001600160a01b0316146106205760405162461bcd60e51b8152600401610617906137ab565b60405180910390fd5b6006546001600160a01b038281169116141561064e5760405162461bcd60e51b815260040161061790613676565b6002546001600160a01b038281169116141561067c5760405162461bcd60e51b815260040161061790613753565b60606106866126bd565b905060005b81518110156106e1578181815181106106a057fe5b60200260200101516001600160a01b0316836001600160a01b031614156106d95760405162461bcd60e51b81526004016106179061381a565b60010161068b565b5061077a6106ed612640565b6040516370a0823160e01b81526001600160a01b038516906370a0823190610719903090600401613585565b60206040518083038186803b15801561073157600080fd5b505afa158015610745573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061076991906134d3565b6001600160a01b03851691906126c2565b5050565b6000805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156108045780601f106107d957610100808354040283529160200191610804565b820191906000526020600020905b8154815290600101906020018083116107e757829003601f168201915b505050505081565b60108054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156108985780601f1061086d57610100808354040283529160200191610898565b820191906000526020600020905b81548152906001019060200180831161087b57829003601f168201915b5050505050905090565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b1580156108f057600080fd5b505afa158015610904573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109289190613348565b6001600160a01b0316336001600160a01b0316148061095f575061094a612640565b6001600160a01b0316336001600160a01b0316145b61097b5760405162461bcd60e51b8152600401610617906137ab565b600d805460ff1916911515919091179055565b6003546001600160a01b03163314806109bf57506109aa612640565b6001600160a01b0316336001600160a01b0316145b6109db5760405162461bcd60e51b8152600401610617906137ab565b600a8190556040517fa68ba126373d04c004c5748c300c9fca12bd444b3d4332e261f3bd2bac4a860090610a109083906138fc565b60405180910390a150565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610a6957600080fd5b505afa158015610a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa19190613348565b6001600160a01b0316336001600160a01b03161480610ad85750610ac3612640565b6001600160a01b0316336001600160a01b0316145b610af45760405162461bcd60e51b8152600401610617906137ab565b61271062ffffff83161115610b0857600080fd5b61271062ffffff82161115610b1c57600080fd5b600f805462ffffff928316600160b81b0262ffffff60b81b1994909316600160a01b0262ffffff60a01b199091161792909216179055565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610ba257600080fd5b505afa158015610bb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bda9190613348565b6001600160a01b0316336001600160a01b03161480610c115750610bfc612640565b6001600160a01b0316336001600160a01b0316145b610c2d5760405162461bcd60e51b8152600401610617906137ab565b7fc8db9c35f716b87af1fbb83f03c78646061931269301fd7ba6dcf189b4cdc2fc81604051610c5c9190613585565b60405180910390a1600180546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b61271081565b600a5481565b6006546001600160a01b031681565b6003546001600160a01b031681565b600f54600160b81b900462ffffff1681565b6002546040516339ebf82360e01b815260009182916001600160a01b03909116906339ebf82390610cfd903090600401613585565b6101206040518083038186803b158015610d1657600080fd5b505afa158015610d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4e9190613409565b604001511180610d6557506000610d6361217b565b115b905090565b604080518082019091526005815264302e342e3360d81b602082015290565b60085481565b6002546000906001600160a01b03163314610dbc5760405162461bcd60e51b815260040161061790613733565b6000610dc7836126e1565b600654909350909150610de4906001600160a01b031633836126c2565b50919050565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610e3857600080fd5b505afa158015610e4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e709190613348565b6001600160a01b0316336001600160a01b03161480610ea75750610e92612640565b6001600160a01b0316336001600160a01b0316145b610ec35760405162461bcd60e51b8152600401610617906137ab565b610ecb6127c5565b565b6003546001600160a01b0316331480610efe5750610ee9612640565b6001600160a01b0316336001600160a01b0316145b610f1a5760405162461bcd60e51b8152600401610617906137ab565b60078190556040517fbb2c369a0355a34b02ab5fce0643150c87e1c8dfe7c918d465591879f57948b190610a109083906138fc565b6005546001600160a01b0316331480610f7257506003546001600160a01b031633145b80610f955750610f80612640565b6001600160a01b0316336001600160a01b0316145b806110365750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015610fe957600080fd5b505afa158015610ffd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110219190613348565b6001600160a01b0316336001600160a01b0316145b806110d75750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561108a57600080fd5b505afa15801561109e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c29190613348565b6001600160a01b0316336001600160a01b0316145b6110f35760405162461bcd60e51b8152600401610617906137ab565b6002546040805163bf3759b560e01b81529051610ecb926001600160a01b03169163bf3759b5916004808301926020929190829003018186803b15801561113957600080fd5b505afa15801561114d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117191906134d3565b612844565b6005546001600160a01b031633148061119957506003546001600160a01b031633145b806111bc57506111a7612640565b6001600160a01b0316336001600160a01b0316145b8061125d5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561121057600080fd5b505afa158015611224573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112489190613348565b6001600160a01b0316336001600160a01b0316145b806112fe5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b1580156112b157600080fd5b505afa1580156112c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e99190613348565b6001600160a01b0316336001600160a01b0316145b61131a5760405162461bcd60e51b8152600401610617906137ab565b6000806000600260009054906101000a90046001600160a01b03166001600160a01b031663bf3759b56040518163ffffffff1660e01b815260040160206040518083038186803b15801561136d57600080fd5b505afa158015611381573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113a591906134d3565b600b5490915060009060ff16156114025760006113c06128d3565b9050828110156113db576113d4838261295e565b93506113f0565b828111156113f0576113ed818461295e565b94505b6113fa838561295e565b915050611413565b61140b826129a9565b919550935090505b6002546040516339ebf82360e01b81526000916001600160a01b0316906339ebf82390611444903090600401613585565b6101206040518083038186803b15801561145d57600080fd5b505afa158015611471573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114959190613409565b60c001516002546040516328766ebf60e21b81529192506001600160a01b03169063a1d9bafc906114ce90889088908790600401613905565b602060405180830381600087803b1580156114e857600080fd5b505af11580156114fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061152091906134d3565b925061152b83612844565b60015460ff16801561154c575060015461010090046001600160a01b031615155b156115fe5760015460405163c70fa00b60e01b81526101009091046001600160a01b03169063c70fa00b9061158d9088908890879089908890600401613936565b60206040518083038186803b1580156115a557600080fd5b505afa1580156115b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115dd9190613380565b6115f95760405162461bcd60e51b8152600401610617906136cc565b611643565b7ff769f6bf659bbbdabf212d830720ce893eedc57f25ebb8e44edf5b300618a35b600160405161162e9190613604565b60405180910390a16001805460ff1916811790555b7f4c0f499ffe6befa0ca7c826b0916cf87bea98de658013e76938489368d60d50985858486604051611678949392919061391b565b60405180910390a15050505050565b736346282db8323a54e840c6c772b4399c9c655c0d81565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b1580156116ed57600080fd5b505afa158015611701573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117259190613348565b6001600160a01b0316336001600160a01b0316148061175c5750611747612640565b6001600160a01b0316336001600160a01b0316145b6117785760405162461bcd60e51b8152600401610617906137ab565b6002811061178557600080fd5b80600114156117b957600f80546001600160a01b03191673ff970a61a04b1ca14834a43f5de4533ebddb5cc81790556117e0565b600f80546001600160a01b03191673fd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb91790555b50565b600b5460ff1681565b6040516370a0823160e01b815260009073ce5f24b7a95e9cba7df4b54e911b4a3dc8cdaf6f906370a0823190611826903090600401613585565b60206040518083038186803b15801561183e57600080fd5b505afa158015611852573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6591906134d3565b60005b919050565b60015460ff1681565b6003546001600160a01b03163314806118b857506118a3612640565b6001600160a01b0316336001600160a01b0316145b6118d45760405162461bcd60e51b8152600401610617906137ab565b6001600160a01b0381166118e757600080fd5b600580546001600160a01b0319166001600160a01b0383161790556040517f2f202ddb4a2e345f6323ed90f8fc8559d770a7abbbeee84dde8aca3351fe715490610a10908390613585565b6003546001600160a01b0316331480611963575061194e612640565b6001600160a01b0316336001600160a01b0316145b61197f5760405162461bcd60e51b8152600401610617906137ab565b61198b6000838361323a565b507f300e67d5a415b6d015a471d9c7b95dd58f3e8290af965e84e0f845de2996dda682826040516119bd92919061360f565b60405180910390a15050565b600c5481565b60095481565b600090565b6003546001600160a01b0316331480611a0b57506119f6612640565b6001600160a01b0316336001600160a01b0316145b611a275760405162461bcd60e51b8152600401610617906137ab565b60098190556040517fd94596337df4c2f0f44d30a7fc5db1c7bb60d9aca4185ed77c6fd96eb45ec29890610a109083906138fc565b6003546001600160a01b0316331480611a8d5750611a78612640565b6001600160a01b0316336001600160a01b0316145b611aa95760405162461bcd60e51b8152600401610617906137ab565b612710811115611ab857600080fd5b600c55565b60075481565b6004546001600160a01b031681565b600e5481565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015611b2657600080fd5b505afa158015611b3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b5e9190613348565b6001600160a01b0316336001600160a01b03161480611b955750611b80612640565b6001600160a01b0316336001600160a01b0316145b611bb15760405162461bcd60e51b8152600401610617906137ab565b7ff769f6bf659bbbdabf212d830720ce893eedc57f25ebb8e44edf5b300618a35b81604051611be09190613604565b60405180910390a16001805460ff1916911515919091179055565b6005546001600160a01b031681565b600f546001600160a01b031681565b60015461010090046001600160a01b031681565b6006546040516370a0823160e01b81526000916001600160a01b0316906370a0823190611826903090600401613585565b6003546001600160a01b0316331480611c8f5750611c7a612640565b6001600160a01b0316336001600160a01b0316145b611cab5760405162461bcd60e51b8152600401610617906137ab565b6001600160a01b038116611cbe57600080fd5b600380546001600160a01b0319166001600160a01b0383161790556040517f352ececae6d7d1e6d26bcf2c549dfd55be1637e9b22dc0cf3b71ddb36097a6b490610a10908390613585565b6002546001600160a01b03163314611d2057600080fd5b6002546040805163fbfa77cf60e01b815290516001600160a01b039283169284169163fbfa77cf916004808301926020929190829003018186803b158015611d6757600080fd5b505afa158015611d7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9f9190613348565b6001600160a01b031614611db257600080fd5b611dbb81612e2e565b6006546040516370a0823160e01b81526117e09183916001600160a01b03909116906370a0823190611df1903090600401613585565b60206040518083038186803b158015611e0957600080fd5b505afa158015611e1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e4191906134d3565b6006546001600160a01b031691906126c2565b600f54600160a01b900462ffffff1681565b6003546001600160a01b03163314611e905760405162461bcd60e51b815260040161061790613651565b6001600160a01b038116611ea357600080fd5b6002546004805460405163095ea7b360e01b81526001600160a01b039384169363095ea7b393611eda9390911691600091016135b3565b602060405180830381600087803b158015611ef457600080fd5b505af1158015611f08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2c9190613380565b50600480546001600160a01b0319166001600160a01b038381169190911780835560025460405163095ea7b360e01b81529083169363095ea7b393611f7793169160001991016135b3565b602060405180830381600087803b158015611f9157600080fd5b505af1158015611fa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc99190613380565b507fafbb66abf8f3b719799940473a4052a3717cdd8e40fb6c8a3faadab316b1a06981604051610a109190613585565b6000612003610cc8565b61200f57506000611879565b6120176132b8565b6002546040516339ebf82360e01b81526001600160a01b03909116906339ebf82390612047903090600401613585565b6101206040518083038186803b15801561206057600080fd5b505afa158015612074573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120989190613409565b90506008546120b48260a001514261295e90919063ffffffff16565b11156120c4576001915050611879565b600e54600260009054906101000a90046001600160a01b03166001600160a01b031663112c1f9b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561211557600080fd5b505afa158015612129573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061214d91906134d3565b111561215d576001915050611879565b600d5460ff1615612172576001915050611879565b50600092915050565b6000610d656121886117ec565b612190611c2d565b90612e77565b6003546001600160a01b03163314806121c757506121b2612640565b6001600160a01b0316336001600160a01b0316145b6121e35760405162461bcd60e51b8152600401610617906137ab565b60088190556040517f5430e11864ad7aa9775b07d12657fe52df9aa2ba734355bd8ef8747be2c800c590610a109083906138fc565b6002546001600160a01b031681565b6003546001600160a01b03163314806122585750612243612640565b6001600160a01b0316336001600160a01b0316145b806122f95750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b1580156122ac57600080fd5b505afa1580156122c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e49190613348565b6001600160a01b0316336001600160a01b0316145b8061239a5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561234d57600080fd5b505afa158015612361573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123859190613348565b6001600160a01b0316336001600160a01b0316145b6123b65760405162461bcd60e51b8152600401610617906137ab565b600b805460ff191660011790556002546040805163507257cd60e11b815290516001600160a01b039092169163a0e4af9a9160048082019260009290919082900301818387803b15801561240957600080fd5b505af115801561241d573d6000803e3d6000fd5b50506040517f97e963041e952738788b9d4871d854d282065b8f90a464928d6528f2e9a4fd0b925060009150a1565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561249a57600080fd5b505afa1580156124ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124d29190613348565b6001600160a01b0316336001600160a01b0316148061250957506124f4612640565b6001600160a01b0316336001600160a01b0316145b6125255760405162461bcd60e51b8152600401610617906137ab565b600e55565b8015806125b25750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e906125609030908690600401613599565b60206040518083038186803b15801561257857600080fd5b505afa15801561258c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125b091906134d3565b155b6125ce5760405162461bcd60e51b81526004016106179061383e565b6126248363095ea7b360e01b84846040516024016125ed9291906135b3565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612e9c565b505050565b60606126388484600085612f2b565b949350505050565b60025460408051635aa6e67560e01b815290516000926001600160a01b031691635aa6e675916004808301926020929190829003018186803b15801561268557600080fd5b505afa158015612699573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d659190613348565b606090565b6126248363a9059cbb60e01b84846040516024016125ed9291906135b3565b60008060006126ee611c2d565b9050808411156127b15760006127026117ec565b905080156127865773ce5f24b7a95e9cba7df4b54e911b4a3dc8cdaf6f632e1a7d4d61273783612732898761295e565b612fef565b6040518263ffffffff1660e01b815260040161275391906138fc565b600060405180830381600087803b15801561276d57600080fd5b505af1158015612781573d6000803e3d6000fd5b505050505b6000612790611c2d565b905061279c8682612fef565b94506127a8868661295e565b935050506127be565b83600092509250506127c0565b505b915091565b6040516335313c2160e11b815273abc000d88f23bb45525e447528dbf656a9d55bf590636a627842906128109073ce5f24b7a95e9cba7df4b54e911b4a3dc8cdaf6f90600401613585565b600060405180830381600087803b15801561282a57600080fd5b505af115801561283e573d6000803e3d6000fd5b50505050565b600b5460ff1615612854576117e0565b600061285e611c2d565b9050801561077a5760405163b6b55f2560e01b815273ce5f24b7a95e9cba7df4b54e911b4a3dc8cdaf6f9063b6b55f259061289d9084906004016138fc565b600060405180830381600087803b1580156128b757600080fd5b505af11580156128cb573d6000803e3d6000fd5b505050505050565b6000806128de6117ec565b9050801561295057604051632e1a7d4d60e01b815273ce5f24b7a95e9cba7df4b54e911b4a3dc8cdaf6f90632e1a7d4d9061291d9084906004016138fc565b600060405180830381600087803b15801561293757600080fd5b505af115801561294b573d6000803e3d6000fd5b505050505b612958611c2d565b91505090565b60006129a083836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613005565b90505b92915050565b60008060006129b66127c5565b6040516370a0823160e01b81526000907311cdb42b0eb46d95f990bedd4695a6e3fa034978906370a08231906129f0903090600401613585565b60206040518083038186803b158015612a0857600080fd5b505afa158015612a1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a4091906134d3565b90508015612abf57600c5415612ab6576000612a73612710612a6d600c548561303190919063ffffffff16565b9061306b565b9050612aa87311cdb42b0eb46d95f990bedd4695a6e3fa034978736346282db8323a54e840c6c772b4399c9c655c0d836126c2565b612ab2828261295e565b9150505b612abf816130ad565b6040516370a0823160e01b815260009073fd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9906370a0823190612af9903090600401613585565b60206040518083038186803b158015612b1157600080fd5b505afa158015612b25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b4991906134d3565b6040516370a0823160e01b815290915060009073ff970a61a04b1ca14834a43f5de4533ebddb5cc8906370a0823190612b86903090600401613585565b60206040518083038186803b158015612b9e57600080fd5b505afa158015612bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd691906134d3565b90506000821180612be75750600081115b15612c8b57604080518082018252828152602081018490529051630b4c7e4d60e01b8152737f90122bf0700f9e7e1f688fe926940e8839f35391630b4c7e4d91612c3791906000906004016135cc565b602060405180830381600087803b158015612c5157600080fd5b505af1158015612c65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c8991906134d3565b505b8615612d31576000612c9b6117ec565b90508015612d165773ce5f24b7a95e9cba7df4b54e911b4a3dc8cdaf6f632e1a7d4d612cc7838b612fef565b6040518263ffffffff1660e01b8152600401612ce391906138fc565b600060405180830381600087803b158015612cfd57600080fd5b505af1158015612d11573d6000803e3d6000fd5b505050505b6000612d20611c2d565b9050612d2c8982612fef565b955050505b6000612d3b61217b565b6002546040516339ebf82360e01b81529192506000916001600160a01b03909116906339ebf82390612d71903090600401613585565b6101206040518083038186803b158015612d8a57600080fd5b505afa158015612d9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc29190613409565b60c00151905080821115612e0957612dda828261295e565b97506000612de6611c2d565b905080612df38a89612e77565b1115612e0357612e016128d3565b505b50612e16565b612e13818361295e565b96505b5050600d805460ff1916905550939592945090925050565b6000612e386117ec565b9050801561077a57604051632e1a7d4d60e01b815273ce5f24b7a95e9cba7df4b54e911b4a3dc8cdaf6f90632e1a7d4d9061289d9084906004016138fc565b6000828201838110156129a05760405162461bcd60e51b815260040161061790613695565b6060612ef1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166126299092919063ffffffff16565b8051909150156126245780806020019051810190612f0f9190613380565b6126245760405162461bcd60e51b8152600401610617906137d0565b6060612f36856131ca565b612f525760405162461bcd60e51b815260040161061790613774565b60006060866001600160a01b03168587604051612f6f9190613569565b60006040518083038185875af1925050503d8060008114612fac576040519150601f19603f3d011682016040523d82523d6000602084013e612fb1565b606091505b50915091508115612fc55791506126389050565b805115612fd55780518082602001fd5b8360405162461bcd60e51b8152600401610617919061363e565b6000818310612ffe57816129a0565b5090919050565b600081848411156130295760405162461bcd60e51b8152600401610617919061363e565b505050900390565b600082613040575060006129a3565b8282028284828161304d57fe5b04146129a05760405162461bcd60e51b8152600401610617906136f2565b60006129a083836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613203565b600f54604051606091613111917311cdb42b0eb46d95f990bedd4695a6e3fa0349789162ffffff600160a01b82048116927382af49447d8a07e3bd95bd0d56f35241523fbab192600160b81b8104909216916001600160a01b031690602001613517565b60408051601f1981840301815260a08301825280835230602084015242838301526060830185905260006080840152905163c04b8d5960e01b815290925073e592427a0aece92de3edee1f18e0157c058615649163c04b8d59916131789190600401613894565b602060405180830381600087803b15801561319257600080fd5b505af11580156131a6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061262491906134d3565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590612638575050151592915050565b600081836132245760405162461bcd60e51b8152600401610617919061363e565b50600083858161323057fe5b0495945050505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061327b5782800160ff198235161785556132a8565b828001600101855582156132a8579182015b828111156132a857823582559160200191906001019061328d565b506132b4929150613304565b5090565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b5b808211156132b45760008155600101613305565b803562ffffff811681146129a357600080fd5b60006020828403121561333d578081fd5b81356129a0816139ac565b600060208284031215613359578081fd5b81516129a0816139ac565b600060208284031215613375578081fd5b81356129a0816139c1565b600060208284031215613391578081fd5b81516129a0816139c1565b600080602083850312156133ae578081fd5b823567ffffffffffffffff808211156133c5578283fd5b818501915085601f8301126133d8578283fd5b8135818111156133e6578384fd5b8660208285010111156133f7578384fd5b60209290920196919550909350505050565b600061012080838503121561341c578182fd5b61342581613959565b9050825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b60008060408385031215613499578182fd5b6134a38484613319565b91506134b28460208501613319565b90509250929050565b6000602082840312156134cc578081fd5b5035919050565b6000602082840312156134e4578081fd5b5051919050565b60008151808452613503816020860160208601613980565b601f01601f19169290920160200192915050565b6bffffffffffffffffffffffff19606096871b811682526001600160e81b031960e896871b8116601484015294871b811660178301529290941b909216602b840152921b909116602e82015260420190565b6000825161357b818460208701613980565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b60608101818460005b60028110156135f45781518352602092830192909101906001016135d5565b5050508260408301529392505050565b901515815260200190565b60006020825282602083015282846040840137818301604090810191909152601f909201601f19160101919050565b6000602082526129a060208301846134eb565b6020808252600b908201526a085cdd1c985d1959da5cdd60aa1b604082015260600190565b602080825260059082015264085dd85b9d60da1b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252600c908201526b216865616c7468636865636b60a01b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b602080825260069082015265085d985d5b1d60d21b604082015260600190565b6020808252600790820152662173686172657360c81b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252600b908201526a08585d5d1a1bdc9a5e995960aa1b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252600a9082015269085c1c9bdd1958dd195960b21b604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b600060208252825160a060208401526138b060c08401826134eb565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b62ffffff91909116815260200190565b90815260200190565b9283526020830191909152604082015260600190565b93845260208401929092526040830152606082015260800190565b948552602085019390935260408401919091526060830152608082015260a00190565b60405181810167ffffffffffffffff8111828210171561397857600080fd5b604052919050565b60005b8381101561399b578181015183820152602001613983565b8381111561283e5750506000910152565b6001600160a01b03811681146117e057600080fd5b80151581146117e057600080fdfea2646970667358221220b0b2dd8460567b9de8623ccdebe7d398a0a201f2c4860a1d20fb11e74e22ccf564736f6c634300060c003300000000000000000000000049448d2b94fb9c4e41a30ad8315d32f46004a34b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000145374726174656779437572766554776f506f6f6c000000000000000000000000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000049448d2b94fb9c4e41a30ad8315d32f46004a34b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000145374726174656779437572766554776f506f6f6c000000000000000000000000
-----Decoded View---------------
Arg [0] : _vaultAddress (address): 0x49448d2b94fb9c4e41a30ad8315d32f46004a34b
Arg [1] : _stratName (string): StrategyCurveTwoPool
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000049448d2b94fb9c4e41a30ad8315d32f46004a34b
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [3] : 5374726174656779437572766554776f506f6f6c000000000000000000000000
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.