More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 27 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Clone Router Str... | 17837328 | 330 days ago | IN | 0 ETH | 0.00808948 | ||||
Clone Router Str... | 17837328 | 330 days ago | IN | 0 ETH | 0.00809274 | ||||
Clone Router Str... | 17837328 | 330 days ago | IN | 0 ETH | 0.00809117 | ||||
Clone Router Str... | 17837328 | 330 days ago | IN | 0 ETH | 0.00809117 | ||||
Clone Router Str... | 17837263 | 330 days ago | IN | 0 ETH | 0.00807272 | ||||
Clone Router Str... | 17837263 | 330 days ago | IN | 0 ETH | 0.00794819 | ||||
Clone Router Str... | 17837263 | 330 days ago | IN | 0 ETH | 0.00807372 | ||||
Clone Router Str... | 17837263 | 330 days ago | IN | 0 ETH | 0.00794842 | ||||
Clone Router Str... | 17837263 | 330 days ago | IN | 0 ETH | 0.00794891 | ||||
Clone Router Str... | 17837263 | 330 days ago | IN | 0 ETH | 0.00794908 | ||||
Set Keeper | 17496595 | 378 days ago | IN | 0 ETH | 0.0006582 | ||||
Clone Router Str... | 17473597 | 381 days ago | IN | 0 ETH | 0.00674113 | ||||
Clone Router Str... | 17468093 | 382 days ago | IN | 0 ETH | 0.00614258 | ||||
Clone Router Str... | 17468090 | 382 days ago | IN | 0 ETH | 0.00564304 | ||||
Clone Router Str... | 17468086 | 382 days ago | IN | 0 ETH | 0.00588609 | ||||
Clone Router Str... | 17468068 | 382 days ago | IN | 0 ETH | 0.00563494 | ||||
Clone Router Str... | 17468062 | 382 days ago | IN | 0 ETH | 0.00592426 | ||||
Clone Router Str... | 17468061 | 382 days ago | IN | 0 ETH | 0.00545744 | ||||
Clone Router Str... | 17468053 | 382 days ago | IN | 0 ETH | 0.00580434 | ||||
Clone Router Str... | 17468053 | 382 days ago | IN | 0 ETH | 0.00580434 | ||||
Clone Router Str... | 17468053 | 382 days ago | IN | 0 ETH | 0.00580451 | ||||
Clone Router Str... | 17468053 | 382 days ago | IN | 0 ETH | 0.00571709 | ||||
Clone Router Str... | 17468053 | 382 days ago | IN | 0 ETH | 0.00576395 | ||||
Clone Router Str... | 17468048 | 382 days ago | IN | 0 ETH | 0.00564248 | ||||
Clone Router Str... | 17468048 | 382 days ago | IN | 0 ETH | 0.00568219 |
Latest 25 internal transactions (View All)
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
StrategyRouterV2
Compiler Version
v0.8.15+commit.e14f2714
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.15; import "https://github.com/yearn/yearn-vaults/blob/v0.4.6/contracts/BaseStrategy.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; interface IVault is IERC20 { function token() external view returns (address); function decimals() external view returns (uint256); function deposit() external; function pricePerShare() external view returns (uint256); function totalAssets() external view returns (uint256); function lockedProfit() external view returns (uint256); function lockedProfitDegradation() external view returns (uint256); function lastReport() external view returns (uint256); function withdraw( uint256 amount, address account, uint256 maxLoss ) external returns (uint256); } interface IOracle { // pull our asset price, in usdc, via yearn's oracle function getPriceUsdcRecommended(address tokenAddress) external view returns (uint256); } interface IHelper { function sharesToAmount(address vault, uint256 shares) external view returns (uint256); function amountToShares(address vault, uint256 amount) external view returns (uint256); } contract StrategyRouterV2 is BaseStrategy { using SafeERC20 for IERC20; /* ========== STATE VARIABLES ========== */ /// @notice The newer yVault we are routing this strategy to. IVault public yVault; /// @notice Max percentage loss we will take, in basis points (100% = 10_000). Default setting is zero. uint256 public maxLoss; /// @notice Address of our share value helper contract, which we use for conversions between shares and underlying amounts. Big 🧠 math here. IHelper public constant shareValueHelper = IHelper(0x444443bae5bB8640677A8cdF94CB8879Fec948Ec); /// @notice Minimum profit size in USDC that we want to harvest. /// @dev Only used in harvestTrigger. uint256 public harvestProfitMinInUsdc; /// @notice Maximum profit size in USDC that we want to harvest (ignore gas price once we get here). /// @dev Only used in harvestTrigger. uint256 public harvestProfitMaxInUsdc; /// @notice Amount we accept as a loss in liquidatePosition if we don't get 100% back due to rounding errors. uint256 public dustThreshold; /// @notice Will only be true on the original deployed contract and not on clones; we don't want to clone a clone. bool public isOriginal = true; // Do I really need to explain this one? string internal strategyName; /* ========== CONSTRUCTOR ========== */ constructor( address _vault, address _yVault, string memory _strategyName ) BaseStrategy(_vault) { _initializeThis(_yVault, _strategyName); } /* ========== CLONING ========== */ event Cloned(address indexed clone); /// @notice Use this to clone an exact copy of this strategy on another vault. /// @param _vault Vault address we want to attach our new strategy to. /// @param _strategist Address to grant the strategist role. /// @param _rewards If we have any strategist rewards, send them here. /// @param _keeper Address to grant the keeper role. /// @param _yVault The newer vault we will route our funds to. /// @param _strategyName Name to use for our new strategy. function cloneRouterStrategy( address _vault, address _strategist, address _rewards, address _keeper, address _yVault, string memory _strategyName ) external virtual returns (address newStrategy) { require(isOriginal); // 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) } StrategyRouterV2(newStrategy).initialize( _vault, _strategist, _rewards, _keeper, _yVault, _strategyName ); emit Cloned(newStrategy); } function initialize( address _vault, address _strategist, address _rewards, address _keeper, address _yVault, string memory _strategyName ) public { require(address(yVault) == address(0)); _initialize(_vault, _strategist, _rewards, _keeper); _initializeThis(_yVault, _strategyName); } function _initializeThis(address _yVault, string memory _strategyName) internal { yVault = IVault(_yVault); strategyName = _strategyName; harvestProfitMinInUsdc = 5_000e6; harvestProfitMaxInUsdc = 50_000e6; dustThreshold = 10; } /* ========== VIEWS ========== */ /// @notice Strategy name. function name() external view override returns (string memory) { return strategyName; } /// @notice Total assets the strategy holds, sum of loose and staked want. function estimatedTotalAssets() public view virtual override returns (uint256) { return balanceOfWant() + valueOfInvestment(); } /// @notice Assets delegated to another vault. Helps to avoid double-counting of TVL. /// @dev While a strategy may have loose want, only donations would be unaccounted for, and thus are not counted here. /// Note that a strategy could also have loose want from a manual withdrawFromYVault() call. function delegatedAssets() public view override returns (uint256) { return vault.strategies(address(this)).totalDebt; } /// @notice Balance of want sitting in our strategy. function balanceOfWant() public view returns (uint256) { return want.balanceOf(address(this)); } /// @notice Balance of underlying we are holding as vault tokens of our delegated vault. function valueOfInvestment() public view virtual returns (uint256) { return shareValueHelper.sharesToAmount( address(yVault), yVault.balanceOf(address(this)) ); } /// @notice Balance of underlying we will gain on our next harvest function claimableProfits() public view returns (uint256 profits) { uint256 assets = estimatedTotalAssets(); uint256 debt = delegatedAssets(); if (assets > debt) { unchecked { profits = assets - debt; } } else { profits = 0; } } /* ========== CORE STRATEGY FUNCTIONS ========== */ function prepareReturn(uint256 _debtOutstanding) internal virtual override returns ( uint256 _profit, uint256 _loss, uint256 _debtPayment ) { // serious loss should never happen, but if it does, let's record it accurately uint256 assets = estimatedTotalAssets(); uint256 debt = delegatedAssets(); // if assets are greater than debt, things are working great! if (assets >= debt) { unchecked { _profit = assets - debt; } _debtPayment = _debtOutstanding; uint256 toFree = _profit + _debtPayment; // freed is math.min(wantBalance, toFree) (uint256 freed, ) = liquidatePosition(toFree); if (toFree > freed) { if (_debtPayment >= freed) { _debtPayment = freed; _profit = 0; } else { unchecked { _profit = freed - _debtPayment; } } } } // if assets are less than debt, we are in trouble. don't worry about withdrawing here, just report losses else { unchecked { _loss = debt - assets; } } } function adjustPosition(uint256 _debtOutstanding) internal virtual override { if (emergencyExit) { return; } uint256 balance = balanceOfWant(); if (balance > 0) { _checkAllowance(address(yVault), address(want), balance); yVault.deposit(); } } function liquidatePosition(uint256 _amountNeeded) internal virtual override returns (uint256 _liquidatedAmount, uint256 _loss) { uint256 balance = balanceOfWant(); if (balance >= _amountNeeded) { return (_amountNeeded, 0); } uint256 toWithdraw; unchecked { toWithdraw = _amountNeeded - balance; } // withdraw the remainder we need _withdrawFromYVault(toWithdraw); uint256 looseWant = balanceOfWant(); // because of slippage, dust-sized losses are acceptable // however, we don't want to take losses for funds stuck in a strategy in the destination vault if (_amountNeeded > looseWant) { uint256 diff = _amountNeeded - looseWant; _liquidatedAmount = looseWant; if (diff < dustThreshold) { _loss = diff; } } else { _liquidatedAmount = _amountNeeded; } } /// @notice Manually withdraw underlying assets from our target vault. /// @dev Only governance or management may call this. /// @param _amount Shares of our target vault to withdraw. function withdrawFromYVault(uint256 _amount) external onlyVaultManagers { _withdrawFromYVault(_amount); } function _withdrawFromYVault(uint256 _amount) internal { if (_amount == 0) { return; } uint256 _balanceOfYShares = yVault.balanceOf(address(this)); uint256 sharesToWithdraw = Math.min( shareValueHelper.amountToShares(address(yVault), _amount), _balanceOfYShares ); if (sharesToWithdraw == 0) { return; } yVault.withdraw(sharesToWithdraw, address(this), maxLoss); } function liquidateAllPositions() internal virtual override returns (uint256 _amountFreed) { // withdraw as much as we can from vault tokens uint256 vaultTokenBalance = yVault.balanceOf(address(this)); if (vaultTokenBalance > 0) { yVault.withdraw(vaultTokenBalance, address(this), maxLoss); } // return our want balance return balanceOfWant(); } function prepareMigration(address _newStrategy) internal virtual override { IERC20(yVault).safeTransfer( _newStrategy, IERC20(yVault).balanceOf(address(this)) ); } function protectedTokens() internal view override returns (address[] memory ret) {} function _checkAllowance( address _contract, address _token, uint256 _amount ) internal { if (IERC20(_token).allowance(address(this), _contract) < _amount) { IERC20(_token).safeApprove(_contract, 0); IERC20(_token).safeApprove(_contract, type(uint256).max); } } /// @notice Convert our keeper's eth cost into want /// @dev We don't use this since we don't factor call cost into our harvestTrigger. /// @param _amtInWei Amount of ether spent. /// @return Value of ether in want. function ethToWant(uint256 _amtInWei) public view virtual override returns (uint256) {} /* ========== KEEP3RS ========== */ /** * @notice * Provide a signal to the keeper that harvest() should be called. * * Don't harvest if a strategy is inactive. * If our profit exceeds our upper limit, then harvest no matter what. For * our lower profit limit, credit threshold, max delay, and manual force trigger, * only harvest if our gas price is acceptable. * * @param callCostinEth The keeper's estimated gas cost to call harvest() (in wei). * @return True if harvest() should be called, false otherwise. */ function harvestTrigger(uint256 callCostinEth) public view override returns (bool) { // Should not trigger if strategy is not active (no assets and no debtRatio). This means we don't need to adjust keeper job. if (!isActive()) { return false; } // harvest if we have a profit to claim at our upper limit without considering gas price uint256 claimableProfit = claimableProfitInUsdc(); if (claimableProfit > harvestProfitMaxInUsdc) { return true; } // check if the base fee gas price is higher than we allow. if it is, block harvests. if (!isBaseFeeAcceptable()) { return false; } // trigger if we want to manually harvest, but only if our gas price is acceptable if (forceHarvestTriggerOnce) { return true; } // harvest if we have a sufficient profit to claim, but only if our gas price is acceptable if (claimableProfit > harvestProfitMinInUsdc) { return true; } StrategyParams memory params = vault.strategies(address(this)); // harvest regardless of profit once we reach our maxDelay if (block.timestamp - params.lastReport > maxReportDelay) { return true; } // harvest our credit if it's above our threshold if (vault.creditAvailable() > creditThreshold) { return true; } // otherwise, we don't harvest return false; } /// @notice Calculates the profit if all claimable assets were sold for USDC (6 decimals). /// @dev Uses yearn's lens oracle, if returned values are strange then troubleshoot there. /// @return Total return in USDC from taking profits on yToken gains. function claimableProfitInUsdc() public view returns (uint256) { IOracle yearnOracle = IOracle(0x83d95e0D5f402511dB06817Aff3f9eA88224B030); // yearn lens oracle uint256 underlyingPrice = yearnOracle.getPriceUsdcRecommended(address(want)); // Oracle returns prices as 6 decimals, so multiply by claimable amount and divide by token decimals return (claimableProfits() * underlyingPrice) / (10**yVault.decimals()); } /* ========== SETTERS ========== */ // These functions are useful for setting parameters of the strategy that may need to be adjusted. /// @notice Set the maximum loss we will accept (due to slippage or locked funds) on a vault withdrawal. /// @dev Generally, this should be zero, and this function will only be used in special/emergency cases. /// @param _maxLoss Max percentage loss we will take, in basis points (100% = 10_000). function setMaxLoss(uint256 _maxLoss) public onlyVaultManagers { maxLoss = _maxLoss; } /// @notice This allows us to set the dust threshold for our strategy. /// @param _dustThreshold This sets what dust is. If we have less than this remaining after withdrawing, accept it as a loss. function setDustThreshold(uint256 _dustThreshold) external onlyVaultManagers { require(_dustThreshold < 10000, "Your size is too much size"); dustThreshold = _dustThreshold; } /** * @notice * Here we set various parameters to optimize our harvestTrigger. * @param _harvestProfitMinInUsdc The amount of profit (in USDC, 6 decimals) * that will trigger a harvest if gas price is acceptable. * @param _harvestProfitMaxInUsdc The amount of profit in USDC that * will trigger a harvest regardless of gas price. */ function setHarvestTriggerParams( uint256 _harvestProfitMinInUsdc, uint256 _harvestProfitMaxInUsdc ) external onlyVaultManagers { harvestProfitMinInUsdc = _harvestProfitMinInUsdc; harvestProfitMaxInUsdc = _harvestProfitMaxInUsdc; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.15; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.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); } interface IBaseFee { function isCurrentBaseFeeAcceptable() 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 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.6"; } /** * @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 UpdatedBaseFeeOracle(address baseFeeOracle); event UpdatedCreditThreshold(uint256 creditThreshold); event ForcedHarvestTrigger(bool triggerState); 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; // See note on `setEmergencyExit()`. bool public emergencyExit; // See note on `isBaseFeeOracleAcceptable()`. address public baseFeeOracle; // See note on `setCreditThreshold()` uint256 public creditThreshold; // See note on `setForceHarvestTriggerOnce` bool public forceHarvestTriggerOnce; // modifiers modifier onlyAuthorized() { _onlyAuthorized(); _; } modifier onlyEmergencyAuthorized() { _onlyEmergencyAuthorized(); _; } modifier onlyStrategist() { _onlyStrategist(); _; } modifier onlyGovernance() { _onlyGovernance(); _; } modifier onlyRewarder() { _onlyRewarder(); _; } modifier onlyKeepers() { _onlyKeepers(); _; } modifier onlyVaultManagers() { _onlyVaultManagers(); _; } function _onlyAuthorized() internal { require(msg.sender == strategist || msg.sender == governance()); } function _onlyEmergencyAuthorized() internal { require(msg.sender == strategist || msg.sender == governance() || msg.sender == vault.guardian() || msg.sender == vault.management()); } function _onlyStrategist() internal { require(msg.sender == strategist); } function _onlyGovernance() internal { require(msg.sender == governance()); } function _onlyRewarder() internal { require(msg.sender == governance() || msg.sender == strategist); } function _onlyKeepers() internal { require( msg.sender == keeper || msg.sender == strategist || msg.sender == governance() || msg.sender == vault.guardian() || msg.sender == vault.management() ); } function _onlyVaultManagers() internal { require(msg.sender == vault.management() || msg.sender == governance()); } constructor(address _vault) { _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, type(uint256).max); // Give Vault unlimited access (might save gas) strategist = _strategist; rewards = _rewards; keeper = _keeper; // initialize variables maxReportDelay = 30 days; creditThreshold = 1_000_000 * 10**vault.decimals(); // set this high by default so we don't get tons of false triggers if not changed vault.approve(rewards, type(uint256).max); // 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 onlyRewarder { require(_rewards != address(0)); vault.approve(rewards, 0); rewards = _rewards; vault.approve(rewards, type(uint256).max); 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 ensure that any significant credit a strategy has from the * vault will be automatically harvested. * * This may only be called by governance or management. * @param _creditThreshold The number of want tokens that will * automatically trigger a harvest. */ function setCreditThreshold(uint256 _creditThreshold) external onlyVaultManagers { creditThreshold = _creditThreshold; emit UpdatedCreditThreshold(_creditThreshold); } /** * @notice * Used to automatically trigger a harvest by our keepers. Can be * useful if gas prices are too high now, and we want to harvest * later once prices have lowered. * * This may only be called by governance or management. * @param _forceHarvestTriggerOnce Value of true tells keepers to harvest * our strategy */ function setForceHarvestTriggerOnce(bool _forceHarvestTriggerOnce) external onlyVaultManagers { forceHarvestTriggerOnce = _forceHarvestTriggerOnce; emit ForcedHarvestTrigger(_forceHarvestTriggerOnce); } /** * @notice * Used to set our baseFeeOracle, which checks the network's current base * fee price to determine whether it is an optimal time to harvest or tend. * * This may only be called by governance or management. * @param _baseFeeOracle Address of our baseFeeOracle */ function setBaseFeeOracle(address _baseFeeOracle) external onlyVaultManagers { baseFeeOracle = _baseFeeOracle; emit UpdatedBaseFeeOracle(_baseFeeOracle); } /** * @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); // It is highly suggested to use the baseFeeOracle here as well. 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 `maxReportDelay`, `creditThreshold` 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. * * This trigger also checks the network's base fee to avoid harvesting during * times of high network congestion. * * Consider use of super.harvestTrigger() in any override to build on top * of this logic instead of replacing it. For example, if using `minReportDelay`. * * 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) { // Should not trigger if strategy is not active (no assets or no debtRatio) if (!isActive()) return false; // check if the base fee gas price is higher than we allow. if it is, block harvests. if (!isBaseFeeAcceptable()) return false; // trigger if we want to manually harvest, but only if our gas price is acceptable if (forceHarvestTriggerOnce) return true; // Should trigger if hasn't been called in a while StrategyParams memory params = vault.strategies(address(this)); if ((block.timestamp - params.lastReport) >= maxReportDelay) return true; // harvest our credit if it's above our threshold or return false return (vault.creditAvailable() > creditThreshold); } /** * @notice * Check if the current network base fee is below our external target. If * not, then harvestTrigger will return false. * @return `true` if `harvest()` should be allowed, `false` otherwise. */ function isBaseFeeAcceptable() public view returns (bool) { if (baseFeeOracle == address(0)) return true; else return IBaseFee(baseFeeOracle).isCurrentBaseFeeAcceptable(); } /** * @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 - amountFreed; } else if (amountFreed > debtOutstanding) { profit = amountFreed - debtOutstanding; } debtPayment = debtOutstanding - loss; } else { // Free up returns for Vault to pull (profit, loss, debtPayment) = prepareReturn(debtOutstanding); } // we're done harvesting, so reset our trigger if we used it forceHarvestTriggerOnce = false; emit ForcedHarvestTrigger(false); // 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; if (vault.strategies(address(this)).debtRatio != 0) { 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) 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) { return clone(_vault, msg.sender, msg.sender, msg.sender); } function clone( address _vault, address _strategist, address _rewards, address _keeper ) public returns (address newStrategy) { require(isOriginal, "!clone"); // 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); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(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 require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://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"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_yVault","type":"address"},{"internalType":"string","name":"_strategyName","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"clone","type":"address"}],"name":"Cloned","type":"event"},{"anonymous":false,"inputs":[],"name":"EmergencyExitEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"triggerState","type":"bool"}],"name":"ForcedHarvestTrigger","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":"address","name":"baseFeeOracle","type":"address"}],"name":"UpdatedBaseFeeOracle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"creditThreshold","type":"uint256"}],"name":"UpdatedCreditThreshold","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":"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":"baseFeeOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimableProfitInUsdc","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimableProfits","outputs":[{"internalType":"uint256","name":"profits","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_strategist","type":"address"},{"internalType":"address","name":"_rewards","type":"address"},{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"address","name":"_yVault","type":"address"},{"internalType":"string","name":"_strategyName","type":"string"}],"name":"cloneRouterStrategy","outputs":[{"internalType":"address","name":"newStrategy","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"creditThreshold","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":"dustThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"_amtInWei","type":"uint256"}],"name":"ethToWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forceHarvestTriggerOnce","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"harvestProfitMaxInUsdc","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvestProfitMinInUsdc","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"callCostinEth","type":"uint256"}],"name":"harvestTrigger","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"healthCheck","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_strategist","type":"address"},{"internalType":"address","name":"_rewards","type":"address"},{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"address","name":"_yVault","type":"address"},{"internalType":"string","name":"_strategyName","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBaseFeeAcceptable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOriginal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLoss","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxReportDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"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":"rewards","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_baseFeeOracle","type":"address"}],"name":"setBaseFeeOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_creditThreshold","type":"uint256"}],"name":"setCreditThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_doHealthCheck","type":"bool"}],"name":"setDoHealthCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dustThreshold","type":"uint256"}],"name":"setDustThreshold","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":"uint256","name":"_harvestProfitMinInUsdc","type":"uint256"},{"internalType":"uint256","name":"_harvestProfitMaxInUsdc","type":"uint256"}],"name":"setHarvestTriggerParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_healthCheck","type":"address"}],"name":"setHealthCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"}],"name":"setKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxLoss","type":"uint256"}],"name":"setMaxLoss","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":"address","name":"_rewards","type":"address"}],"name":"setRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategist","type":"address"}],"name":"setStrategist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shareValueHelper","outputs":[{"internalType":"contract IHelper","name":"","type":"address"}],"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":"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":"valueOfInvestment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract VaultAPI","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"want","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountNeeded","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"_loss","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawFromYVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"yVault","outputs":[{"internalType":"contract IVault","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040526010805460ff191660011790553480156200001e57600080fd5b506040516200400a3803806200400a833981016040819052620000419162000752565b82620000508133808062000066565b506200005d8282620002d1565b50505062000b87565b6006546001600160a01b031615620000c55760405162461bcd60e51b815260206004820152601c60248201527f537472617465677920616c726561647920696e697469616c697a65640000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b03861690811790915560408051637e062a3560e11b8152905163fc0c546a916004808201926020929091908290030181865afa1580156200011f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000145919062000832565b600680546001600160a01b0319166001600160a01b039290921691821790556200017f90856000196200031b602090811b62001d4717901c565b600380546001600160a01b038086166001600160a01b031992831617909255600480548584169083161781556005805485851693169290921790915562278d006008556002546040805163313ce56760e01b81529051919093169263313ce56792818101926020929091908290030181865afa15801562000204573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022a919062000857565b6200023790600a62000986565b6200024690620f424062000994565b600a556002546004805460405163095ea7b360e01b81526001600160a01b039182169281019290925260001960248301529091169063095ea7b3906044016020604051808303816000875af1158015620002a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ca9190620009b6565b5050505050565b600b8054610100600160a81b0319166101006001600160a01b038516021790556011620002ff828262000a68565b505064012a05f200600d5550640ba43b7400600e55600a600f55565b801580620003995750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa15801562000371573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000397919062000857565b155b6200040d5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401620000bc565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b17909152620004659185916200046a16565b505050565b6000620004c6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200054860201b62001e94179092919060201c565b805190915015620004655780806020019051810190620004e79190620009b6565b620004655760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401620000bc565b606062000559848460008562000561565b949350505050565b606082471015620005c45760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401620000bc565b600080866001600160a01b03168587604051620005e2919062000b34565b60006040518083038185875af1925050503d806000811462000621576040519150601f19603f3d011682016040523d82523d6000602084013e62000626565b606091505b5090925090506200063a8783838762000645565b979650505050505050565b60608315620006b9578251600003620006b1576001600160a01b0385163b620006b15760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620000bc565b508162000559565b620005598383815115620006d05781518083602001fd5b8060405162461bcd60e51b8152600401620000bc919062000b52565b80516001600160a01b03811681146200070457600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200073c57818101518382015260200162000722565b838111156200074c576000848401525b50505050565b6000806000606084860312156200076857600080fd5b6200077384620006ec565b92506200078360208501620006ec565b60408501519092506001600160401b0380821115620007a157600080fd5b818601915086601f830112620007b657600080fd5b815181811115620007cb57620007cb62000709565b604051601f8201601f19908116603f01168101908382118183101715620007f657620007f662000709565b816040528281528960208487010111156200081057600080fd5b620008238360208301602088016200071f565b80955050505050509250925092565b6000602082840312156200084557600080fd5b6200085082620006ec565b9392505050565b6000602082840312156200086a57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600181815b80851115620008c8578160001904821115620008ac57620008ac62000871565b80851615620008ba57918102915b93841c93908002906200088c565b509250929050565b600082620008e15750600162000980565b81620008f05750600062000980565b8160018114620009095760028114620009145762000934565b600191505062000980565b60ff84111562000928576200092862000871565b50506001821b62000980565b5060208310610133831016604e8410600b841016171562000959575081810a62000980565b62000965838362000887565b80600019048211156200097c576200097c62000871565b0290505b92915050565b6000620008508383620008d0565b6000816000190483118215151615620009b157620009b162000871565b500290565b600060208284031215620009c957600080fd5b815180151581146200085057600080fd5b600181811c90821680620009ef57607f821691505b60208210810362000a1057634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200046557600081815260208120601f850160051c8101602086101562000a3f5750805b601f850160051c820191505b8181101562000a605782815560010162000a4b565b505050505050565b81516001600160401b0381111562000a845762000a8462000709565b62000a9c8162000a958454620009da565b8462000a16565b602080601f83116001811462000ad4576000841562000abb5750858301515b600019600386901b1c1916600185901b17855562000a60565b600085815260208120601f198616915b8281101562000b055788860151825594840194600190910190840162000ae4565b508582101562000b245787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000825162000b488184602087016200071f565b9190910192915050565b602081526000825180602084015262000b738160408501602087016200071f565b601f01601f19169190910160400192915050565b6134738062000b976000396000f3fe608060405234801561001057600080fd5b50600436106103835760003560e01c80638aa091f5116101de578063c1a3d44c1161010f578063ee6497f1116100ad578063fa4e2df91161007c578063fa4e2df91461070e578063fbfa77cf14610717578063fcf2d0ad1461072a578063fe2508a61461073257600080fd5b8063ee6497f1146106d8578063efbb5cb0146106eb578063f017c92f146106f3578063f5f5ed171461070657600080fd5b8063d6cb1f6f116100e9578063d6cb1f6f1461068e578063e8462e8f146106a9578063ec38a862146106b2578063ed882c2b146106c557600080fd5b8063c1a3d44c14610660578063c7b9d53014610668578063ce5494bb1461067b57600080fd5b8063a763cf5b1161017c578063aced166111610156578063aced16611461061a578063ad7e55ba1461062d578063b252720b14610640578063b57621141461065857600080fd5b8063a763cf5b146105f1578063aa5480cf146105fe578063ac00ff261461060757600080fd5b806395326e2d116101b857806395326e2d146105ba57806395e80c50146105c25780639ec5a894146105cb5780639f450b5a146105de57600080fd5b80638aa091f51461058c5780638cb14bff1461059f5780638e6350e2146105b257600080fd5b806333303f8e116102b8578063650d188011610256578063748747e611610230578063748747e614610540578063750521f514610553578063780022a014610566578063826cddf61461057457600080fd5b8063650d1880146105125780636718835f146105265780636f392ce71461053357600080fd5b80634641257d116102925780634641257d146104e15780635641ec03146104e95780635783fe39146104f65780635d130ec6146104ff57600080fd5b806333303f8e146104ae57806339a172a8146104c6578063440368a3146104d957600080fd5b80631fe4a6861161032557806325829410116102ff578063258294101461046957806328b7ccf71461048a578063299b1e25146104935780632e1a7d4d1461049b57600080fd5b80631fe4a6861461042b57806322f3e2d41461043e57806324be66281461045657600080fd5b8063090c492211610361578063090c4922146103c35780630ada4dab146103da57806311bc8245146103ed5780631f1fcd511461040057600080fd5b806301681a621461038857806303ee438c1461039d57806306fdde03146103bb575b600080fd5b61039b610396366004612c6c565b610745565b005b6103a56108f0565b6040516103b29190612ce8565b60405180910390f35b6103a561097e565b6103cc600d5481565b6040519081526020016103b2565b61039b6103e8366004612d09565b610a10565b61039b6103fb366004612c6c565b610a60565b600654610413906001600160a01b031681565b6040516001600160a01b0390911681526020016103b2565b600354610413906001600160a01b031681565b610446610acc565b60405190151581526020016103b2565b61039b610464366004612d26565b610b5a565b60408051808201909152600581526418171a171b60d91b60208201526103a5565b6103cc60085481565b6103cc610b67565b6103cc6104a9366004612d26565b610b98565b600b546104139061010090046001600160a01b031681565b61039b6104d4366004612d26565b610c0c565b61039b610c49565b61039b610cc7565b6009546104469060ff1681565b6103cc600c5481565b61039b61050d366004612db0565b611075565b610446610520366004612d26565b50600090565b6001546104469060ff1681565b6010546104469060ff1681565b61039b61054e366004612c6c565b6110ae565b61039b610561366004612ea1565b611117565b6103cc610520366004612d26565b6009546104139061010090046001600160a01b031681565b61041361059a366004612db0565b61116a565b61039b6105ad366004612d26565b61126e565b6103cc611282565b6104466112f9565b6103cc60075481565b600454610413906001600160a01b031681565b61039b6105ec366004612c6c565b61138e565b600b546104469060ff1681565b6103cc600a5481565b61039b610615366004612d09565b6113ec565b600554610413906001600160a01b031681565b61039b61063b366004612d26565b61143c565b6001546104139061010090046001600160a01b031681565b6103cc61149a565b6103cc6115c9565b61039b610676366004612c6c565b611637565b61039b610689366004612c6c565b6116a0565b61041373444443bae5bb8640677a8cdf94cb8879fec948ec81565b6103cc600f5481565b61039b6106c0366004612c6c565b6117c8565b6104466106d3366004612d26565b611926565b61039b6106e6366004612f13565b611abe565b6103cc611ad1565b61039b610701366004612d26565b611aed565b6103cc611b2a565b6103cc600e5481565b600254610413906001600160a01b031681565b61039b611beb565b61039b610740366004612d26565b611d0a565b61074d611eab565b6006546001600160a01b03908116908216036107985760405162461bcd60e51b8152602060048201526005602482015264085dd85b9d60da1b60448201526064015b60405180910390fd5b6002546001600160a01b03908116908216036107e05760405162461bcd60e51b81526020600482015260076024820152662173686172657360c81b604482015260640161078f565b606060005b81518110156108675781818151811061080057610800612f35565b60200260200101516001600160a01b0316836001600160a01b0316036108555760405162461bcd60e51b815260206004820152600a602482015269085c1c9bdd1958dd195960b21b604482015260640161078f565b8061085f81612f61565b9150506107e5565b506108ec610873611ed0565b6040516370a0823160e01b81523060048201526001600160a01b038516906370a0823190602401602060405180830381865afa1580156108b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108db9190612f7a565b6001600160a01b0385169190611f3e565b5050565b600080546108fd90612f93565b80601f016020809104026020016040519081016040528092919081815260200182805461092990612f93565b80156109765780601f1061094b57610100808354040283529160200191610976565b820191906000526020600020905b81548152906001019060200180831161095957829003601f168201915b505050505081565b60606011805461098d90612f93565b80601f01602080910402602001604051908101604052809291908181526020018280546109b990612f93565b8015610a065780601f106109db57610100808354040283529160200191610a06565b820191906000526020600020905b8154815290600101906020018083116109e957829003601f168201915b5050505050905090565b610a18611f6e565b600b805460ff19168215159081179091556040519081527f6ad28df1b554fa6cacd46ae82fa811748d53798feeb437ddf234bf3083953319906020015b60405180910390a150565b610a68611f6e565b6040516001600160a01b03821681527fc8db9c35f716b87af1fbb83f03c78646061931269301fd7ba6dcf189b4cdc2fc9060200160405180910390a1600180546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b6002546040516339ebf82360e01b815230600482015260009182916001600160a01b03909116906339ebf8239060240161012060405180830381865afa158015610b1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3e9190612fc7565b604001511180610b5557506000610b53611ad1565b115b905090565b610b62611f6e565b600c55565b600080610b72611ad1565b90506000610b7e611282565b905080821115610b8f579003919050565b60009250505090565b6002546000906001600160a01b03163314610bde5760405162461bcd60e51b8152602060048201526006602482015265085d985d5b1d60d21b604482015260640161078f565b6000610be983612010565b600654909350909150610c06906001600160a01b03163383611f3e565b50919050565b610c14612082565b60078190556040518181527fbb2c369a0355a34b02ab5fce0643150c87e1c8dfe7c918d465591879f57948b190602001610a55565b610c5161209e565b6002546040805163bf3759b560e01b81529051610cc5926001600160a01b03169163bf3759b59160048083019260209291908290030181865afa158015610c9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc09190612f7a565b6121f3565b565b610ccf61209e565b6000806000600260009054906101000a90046001600160a01b03166001600160a01b031663bf3759b56040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4b9190612f7a565b60095490915060009060ff1615610da8576000610d66612299565b905082811015610d8157610d7a8184613042565b9350610d96565b82811115610d9657610d938382613042565b94505b610da08484613042565b915050610db9565b610db1826123aa565b919550935090505b600b805460ff19169055604051600081527f6ad28df1b554fa6cacd46ae82fa811748d53798feeb437ddf234bf30839533199060200160405180910390a16002546040516339ebf82360e01b81523060048201526000916001600160a01b0316906339ebf8239060240161012060405180830381865afa158015610e41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e659190612fc7565b60c001516002546040516328766ebf60e21b81526004810188905260248101879052604481018590529192506001600160a01b03169063a1d9bafc906064016020604051808303816000875af1158015610ec3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee79190612f7a565b9250610ef2836121f3565b60015460ff168015610f13575060015461010090046001600160a01b031615155b15610fe55760015460405163c70fa00b60e01b815260048101879052602481018690526044810184905260648101859052608481018390526101009091046001600160a01b03169063c70fa00b9060a401602060405180830381865afa158015610f81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa59190613059565b610fe05760405162461bcd60e51b815260206004820152600c60248201526b216865616c7468636865636b60a01b604482015260640161078f565b611026565b604051600181527ff769f6bf659bbbdabf212d830720ce893eedc57f25ebb8e44edf5b300618a35b9060200160405180910390a16001805460ff1916811790555b6040805186815260208101869052908101839052606081018490527f4c0f499ffe6befa0ca7c826b0916cf87bea98de658013e76938489368d60d5099060800160405180910390a15050505050565b600b5461010090046001600160a01b03161561109057600080fd5b61109c86868686612428565b6110a68282612672565b505050505050565b6110b6612082565b6001600160a01b0381166110c957600080fd5b600580546001600160a01b0319166001600160a01b0383169081179091556040519081527f2f202ddb4a2e345f6323ed90f8fc8559d770a7abbbeee84dde8aca3351fe715490602001610a55565b61111f612082565b600061112c8284836130bc565b507f300e67d5a415b6d015a471d9c7b95dd58f3e8290af965e84e0f845de2996dda6828260405161115e92919061317c565b60405180910390a15050565b60105460009060ff1661117c57600080fd5b604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81523060601b601482018190526e5af43d82803e903d91602b57fd5bf360881b6028830152906037816000f0604051632e89876360e11b81529093506001600160a01b0384169150635d130ec6906111fd908b908b908b908b908b908b906004016131ab565b600060405180830381600087803b15801561121757600080fd5b505af115801561122b573d6000803e3d6000fd5b50506040516001600160a01b03851692507f783540fb4221a3238720dc7038937d0d79982bcf895274aa6ad179f82cf0d53c9150600090a2509695505050505050565b611276611f6e565b61127f816126ba565b50565b6002546040516339ebf82360e01b81523060048201526000916001600160a01b0316906339ebf8239060240161012060405180830381865afa1580156112cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f09190612fc7565b60c00151905090565b60095460009061010090046001600160a01b03166113175750600190565b600960019054906101000a90046001600160a01b03166001600160a01b03166334a9e75c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561136a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b559190613059565b611396611f6e565b60098054610100600160a81b0319166101006001600160a01b038416908102919091179091556040519081527f711be97287cb9ec921887b9be36e148e1a27c6b158547b22b9704ffc54447a0f90602001610a55565b6113f4611f6e565b60405181151581527ff769f6bf659bbbdabf212d830720ce893eedc57f25ebb8e44edf5b300618a35b9060200160405180910390a16001805460ff1916911515919091179055565b611444611f6e565b61271081106114955760405162461bcd60e51b815260206004820152601a60248201527f596f75722073697a6520697320746f6f206d7563682073697a65000000000000604482015260640161078f565b600f55565b600654604051632415d18360e11b81526001600160a01b0390911660048201526000907383d95e0d5f402511db06817aff3f9ea88224b030908290829063482ba30690602401602060405180830381865afa1580156114fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115219190612f7a565b9050600b60019054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611576573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159a9190612f7a565b6115a590600a6132df565b816115ae610b67565b6115b891906132eb565b6115c2919061330a565b9250505090565b6006546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a08231906024015b602060405180830381865afa158015611613573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b559190612f7a565b61163f612082565b6001600160a01b03811661165257600080fd5b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527f352ececae6d7d1e6d26bcf2c549dfd55be1637e9b22dc0cf3b71ddb36097a6b490602001610a55565b6002546001600160a01b031633146116b757600080fd5b6002546040805163fbfa77cf60e01b815290516001600160a01b039283169284169163fbfa77cf9160048083019260209291908290030181865afa158015611703573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611727919061332c565b6001600160a01b03161461173a57600080fd5b6117438161286b565b6006546040516370a0823160e01b815230600482015261127f9183916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611791573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b59190612f7a565b6006546001600160a01b03169190611f3e565b6117d06128f9565b6001600160a01b0381166117e357600080fd5b6002546004805460405163095ea7b360e01b81526001600160a01b0391821692810192909252600060248301529091169063095ea7b3906044016020604051808303816000875af115801561183c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118609190613059565b50600480546001600160a01b0319166001600160a01b03838116918217835560025460405163095ea7b360e01b8152938401929092526000196024840152169063095ea7b3906044016020604051808303816000875af11580156118c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ec9190613059565b506040516001600160a01b03821681527fafbb66abf8f3b719799940473a4052a3717cdd8e40fb6c8a3faadab316b1a06990602001610a55565b6000611930610acc565b61193c57506000919050565b600061194661149a565b9050600e5481111561195b5750600192915050565b6119636112f9565b6119705750600092915050565b600b5460ff16156119845750600192915050565b600d548111156119975750600192915050565b6002546040516339ebf82360e01b81523060048201526000916001600160a01b0316906339ebf8239060240161012060405180830381865afa1580156119e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a059190612fc7565b90506008548160a0015142611a1a9190613042565b1115611a2a575060019392505050565b600a54600260009054906101000a90046001600160a01b03166001600160a01b031663112c1f9b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa49190612f7a565b1115611ab4575060019392505050565b5060009392505050565b611ac6611f6e565b600d91909155600e55565b6000611adb611b2a565b611ae36115c9565b610b559190613349565b611af5612082565b60088190556040518181527f5430e11864ad7aa9775b07d12657fe52df9aa2ba734355bd8ef8747be2c800c590602001610a55565b600b546040516370a0823160e01b815230600482015260009173444443bae5bb8640677a8cdf94cb8879fec948ec9163d3d83fa69161010090046001600160a01b03169081906370a0823190602401602060405180830381865afa158015611b96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bba9190612f7a565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016115f6565b611bf3612932565b6009805460ff191660011790556002546040516339ebf82360e01b81523060048201526001600160a01b03909116906339ebf8239060240161012060405180830381865afa158015611c49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c6d9190612fc7565b6040015115611cdf57600260009054906101000a90046001600160a01b03166001600160a01b031663a0e4af9a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611cc657600080fd5b505af1158015611cda573d6000803e3d6000fd5b505050505b6040517f97e963041e952738788b9d4871d854d282065b8f90a464928d6528f2e9a4fd0b90600090a1565b611d12611f6e565b600a8190556040518181527fe5ef7832c564a10cbe7b4f1e01ac33a406cb63fcf430a97a9af8616d150af5f390602001610a55565b801580611dc15750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611d9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbf9190612f7a565b155b611e2c5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606482015260840161078f565b6040516001600160a01b038316602482015260448101829052611e8f90849063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261294e565b505050565b6060611ea38484600085612a20565b949350505050565b611eb3611ed0565b6001600160a01b0316336001600160a01b031614610cc557600080fd5b60025460408051635aa6e67560e01b815290516000926001600160a01b031691635aa6e6759160048083019260209291908290030181865afa158015611f1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b55919061332c565b6040516001600160a01b038316602482015260448101829052611e8f90849063a9059cbb60e01b90606401611e58565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fe5919061332c565b6001600160a01b0316336001600160a01b031614806120075750611eb3611ed0565b610cc557600080fd5b600080600061201d6115c9565b905083811061203157509192600092509050565b80840361203d816126ba565b60006120476115c9565b90508086111561207657600061205d8288613042565b9050819550600f54811015612070578094505b5061207a565b8594505b505050915091565b6003546001600160a01b03163314806120075750611eb3611ed0565b6005546001600160a01b03163314806120c157506003546001600160a01b031633145b806120e457506120cf611ed0565b6001600160a01b0316336001600160a01b0316145b806121765750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa15801561213d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612161919061332c565b6001600160a01b0316336001600160a01b0316145b806120075750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121cf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eb3919061332c565b60095460ff16156122015750565b600061220b6115c9565b905080156108ec57600b54600654612235916001600160a01b036101009091048116911683612afb565b600b60019054906101000a90046001600160a01b03166001600160a01b031663d0e30db06040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561228557600080fd5b505af11580156110a6573d6000803e3d6000fd5b600b546040516370a0823160e01b815230600482015260009182916101009091046001600160a01b0316906370a0823190602401602060405180830381865afa1580156122ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230e9190612f7a565b9050801561239c57600b54600c54604051631cc6d2f960e31b81526004810184905230602482015260448101919091526101009091046001600160a01b03169063e63697c8906064016020604051808303816000875af1158015612376573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061239a9190612f7a565b505b6123a46115c9565b91505090565b6000806000806123b8611ad1565b905060006123c4611282565b905080821061241957808203945085925060006123e18487613349565b905060006123ee82612010565b509050808211156124125780851061240c5780945060009650612412565b84810396505b505061241f565b81810393505b50509193909250565b6006546001600160a01b0316156124815760405162461bcd60e51b815260206004820152601c60248201527f537472617465677920616c726561647920696e697469616c697a656400000000604482015260640161078f565b600280546001600160a01b0319166001600160a01b03861690811790915560408051637e062a3560e11b8152905163fc0c546a916004808201926020929091908290030181865afa1580156124da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124fe919061332c565b600680546001600160a01b0319166001600160a01b0392909216918217905561252a9085600019611d47565b600380546001600160a01b038086166001600160a01b031992831617909255600480548584169083161781556005805485851693169290921790915562278d006008556002546040805163313ce56760e01b81529051919093169263313ce56792818101926020929091908290030181865afa1580156125ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d29190612f7a565b6125dd90600a6132df565b6125ea90620f42406132eb565b600a556002546004805460405163095ea7b360e01b81526001600160a01b039182169281019290925260001960248301529091169063095ea7b3906044016020604051808303816000875af1158015612647573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266b9190613059565b5050505050565b600b8054610100600160a81b0319166101006001600160a01b03851602179055601161269e8282613361565b505064012a05f200600d5550640ba43b7400600e55600a600f55565b806000036126c55750565b600b546040516370a0823160e01b815230600482015260009161010090046001600160a01b0316906370a0823190602401602060405180830381865afa158015612713573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127379190612f7a565b600b54604051632967214160e21b81526101009091046001600160a01b03166004820152602481018490529091506000906127d29073444443bae5bb8640677a8cdf94cb8879fec948ec9063a59c850490604401602060405180830381865afa1580156127a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127cc9190612f7a565b83612b9f565b9050806000036127e157505050565b600b54600c54604051631cc6d2f960e31b81526004810184905230602482015260448101919091526101009091046001600160a01b03169063e63697c8906064016020604051808303816000875af1158015612841573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128659190612f7a565b50505050565b600b546040516370a0823160e01b815230600482015261127f9183916101009091046001600160a01b0316906370a0823190602401602060405180830381865afa1580156128bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128e19190612f7a565b600b5461010090046001600160a01b03169190611f3e565b612901611ed0565b6001600160a01b0316336001600160a01b0316148061200757506003546001600160a01b03163314610cc557600080fd5b6003546001600160a01b03163314806120e457506120cf611ed0565b60006129a3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611e949092919063ffffffff16565b805190915015611e8f57808060200190518101906129c19190613059565b611e8f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161078f565b606082471015612a815760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161078f565b600080866001600160a01b03168587604051612a9d9190613421565b60006040518083038185875af1925050503d8060008114612ada576040519150601f19603f3d011682016040523d82523d6000602084013e612adf565b606091505b5091509150612af087838387612bb9565b979650505050505050565b604051636eb1769f60e11b81523060048201526001600160a01b03848116602483015282919084169063dd62ed3e90604401602060405180830381865afa158015612b4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6e9190612f7a565b1015611e8f57612b896001600160a01b038316846000611d47565b611e8f6001600160a01b03831684600019611d47565b6000818310612bae5781612bb0565b825b90505b92915050565b60608315612c28578251600003612c21576001600160a01b0385163b612c215760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161078f565b5081611ea3565b611ea38383815115612c3d5781518083602001fd5b8060405162461bcd60e51b815260040161078f9190612ce8565b6001600160a01b038116811461127f57600080fd5b600060208284031215612c7e57600080fd5b8135612c8981612c57565b9392505050565b60005b83811015612cab578181015183820152602001612c93565b838111156128655750506000910152565b60008151808452612cd4816020860160208601612c90565b601f01601f19169290920160200192915050565b602081526000612bb06020830184612cbc565b801515811461127f57600080fd5b600060208284031215612d1b57600080fd5b8135612c8981612cfb565b600060208284031215612d3857600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715612d7957612d79612d3f565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715612da857612da8612d3f565b604052919050565b60008060008060008060c08789031215612dc957600080fd5b8635612dd481612c57565b9550602087810135612de581612c57565b95506040880135612df581612c57565b94506060880135612e0581612c57565b93506080880135612e1581612c57565b925060a088013567ffffffffffffffff80821115612e3257600080fd5b818a0191508a601f830112612e4657600080fd5b813581811115612e5857612e58612d3f565b612e6a601f8201601f19168501612d7f565b91508082528b84828501011115612e8057600080fd5b80848401858401376000848284010152508093505050509295509295509295565b60008060208385031215612eb457600080fd5b823567ffffffffffffffff80821115612ecc57600080fd5b818501915085601f830112612ee057600080fd5b813581811115612eef57600080fd5b866020828501011115612f0157600080fd5b60209290920196919550909350505050565b60008060408385031215612f2657600080fd5b50508035926020909101359150565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612f7357612f73612f4b565b5060010190565b600060208284031215612f8c57600080fd5b5051919050565b600181811c90821680612fa757607f821691505b602082108103610c0657634e487b7160e01b600052602260045260246000fd5b60006101208284031215612fda57600080fd5b612fe2612d55565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b60008282101561305457613054612f4b565b500390565b60006020828403121561306b57600080fd5b8151612c8981612cfb565b601f821115611e8f57600081815260208120601f850160051c8101602086101561309d5750805b601f850160051c820191505b818110156110a6578281556001016130a9565b67ffffffffffffffff8311156130d4576130d4612d3f565b6130e8836130e28354612f93565b83613076565b6000601f84116001811461311c57600085156131045750838201355b600019600387901b1c1916600186901b17835561266b565b600083815260209020601f19861690835b8281101561314d578685013582556020948501946001909201910161312d565b508682101561316a5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b6001600160a01b0387811682528681166020830152858116604083015284811660608301528316608082015260c060a082018190526000906131ef90830184612cbc565b98975050505050505050565b600181815b8085111561323657816000190482111561321c5761321c612f4b565b8085161561322957918102915b93841c9390800290613200565b509250929050565b60008261324d57506001612bb3565b8161325a57506000612bb3565b8160018114613270576002811461327a57613296565b6001915050612bb3565b60ff84111561328b5761328b612f4b565b50506001821b612bb3565b5060208310610133831016604e8410600b84101617156132b9575081810a612bb3565b6132c383836131fb565b80600019048211156132d7576132d7612f4b565b029392505050565b6000612bb0838361323e565b600081600019048311821515161561330557613305612f4b565b500290565b60008261332757634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561333e57600080fd5b8151612c8981612c57565b6000821982111561335c5761335c612f4b565b500190565b815167ffffffffffffffff81111561337b5761337b612d3f565b61338f816133898454612f93565b84613076565b602080601f8311600181146133c457600084156133ac5750858301515b600019600386901b1c1916600185901b1785556110a6565b600085815260208120601f198616915b828110156133f3578886015182559484019460019091019084016133d4565b50858210156134115787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008251613433818460208701612c90565b919091019291505056fea264697066735822122036aa1d7c57341d491068eb52b81162d96db22a453d81893d0bf4e46d9779124664736f6c634300080f0033000000000000000000000000e537b5cc158eb71037d4125bdd7538421981e6aa0000000000000000000000008078198fc424986ae89ce4a910fc109587b6abf3000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000185374726174656779526f7574657256322d3343727970746f0000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103835760003560e01c80638aa091f5116101de578063c1a3d44c1161010f578063ee6497f1116100ad578063fa4e2df91161007c578063fa4e2df91461070e578063fbfa77cf14610717578063fcf2d0ad1461072a578063fe2508a61461073257600080fd5b8063ee6497f1146106d8578063efbb5cb0146106eb578063f017c92f146106f3578063f5f5ed171461070657600080fd5b8063d6cb1f6f116100e9578063d6cb1f6f1461068e578063e8462e8f146106a9578063ec38a862146106b2578063ed882c2b146106c557600080fd5b8063c1a3d44c14610660578063c7b9d53014610668578063ce5494bb1461067b57600080fd5b8063a763cf5b1161017c578063aced166111610156578063aced16611461061a578063ad7e55ba1461062d578063b252720b14610640578063b57621141461065857600080fd5b8063a763cf5b146105f1578063aa5480cf146105fe578063ac00ff261461060757600080fd5b806395326e2d116101b857806395326e2d146105ba57806395e80c50146105c25780639ec5a894146105cb5780639f450b5a146105de57600080fd5b80638aa091f51461058c5780638cb14bff1461059f5780638e6350e2146105b257600080fd5b806333303f8e116102b8578063650d188011610256578063748747e611610230578063748747e614610540578063750521f514610553578063780022a014610566578063826cddf61461057457600080fd5b8063650d1880146105125780636718835f146105265780636f392ce71461053357600080fd5b80634641257d116102925780634641257d146104e15780635641ec03146104e95780635783fe39146104f65780635d130ec6146104ff57600080fd5b806333303f8e146104ae57806339a172a8146104c6578063440368a3146104d957600080fd5b80631fe4a6861161032557806325829410116102ff578063258294101461046957806328b7ccf71461048a578063299b1e25146104935780632e1a7d4d1461049b57600080fd5b80631fe4a6861461042b57806322f3e2d41461043e57806324be66281461045657600080fd5b8063090c492211610361578063090c4922146103c35780630ada4dab146103da57806311bc8245146103ed5780631f1fcd511461040057600080fd5b806301681a621461038857806303ee438c1461039d57806306fdde03146103bb575b600080fd5b61039b610396366004612c6c565b610745565b005b6103a56108f0565b6040516103b29190612ce8565b60405180910390f35b6103a561097e565b6103cc600d5481565b6040519081526020016103b2565b61039b6103e8366004612d09565b610a10565b61039b6103fb366004612c6c565b610a60565b600654610413906001600160a01b031681565b6040516001600160a01b0390911681526020016103b2565b600354610413906001600160a01b031681565b610446610acc565b60405190151581526020016103b2565b61039b610464366004612d26565b610b5a565b60408051808201909152600581526418171a171b60d91b60208201526103a5565b6103cc60085481565b6103cc610b67565b6103cc6104a9366004612d26565b610b98565b600b546104139061010090046001600160a01b031681565b61039b6104d4366004612d26565b610c0c565b61039b610c49565b61039b610cc7565b6009546104469060ff1681565b6103cc600c5481565b61039b61050d366004612db0565b611075565b610446610520366004612d26565b50600090565b6001546104469060ff1681565b6010546104469060ff1681565b61039b61054e366004612c6c565b6110ae565b61039b610561366004612ea1565b611117565b6103cc610520366004612d26565b6009546104139061010090046001600160a01b031681565b61041361059a366004612db0565b61116a565b61039b6105ad366004612d26565b61126e565b6103cc611282565b6104466112f9565b6103cc60075481565b600454610413906001600160a01b031681565b61039b6105ec366004612c6c565b61138e565b600b546104469060ff1681565b6103cc600a5481565b61039b610615366004612d09565b6113ec565b600554610413906001600160a01b031681565b61039b61063b366004612d26565b61143c565b6001546104139061010090046001600160a01b031681565b6103cc61149a565b6103cc6115c9565b61039b610676366004612c6c565b611637565b61039b610689366004612c6c565b6116a0565b61041373444443bae5bb8640677a8cdf94cb8879fec948ec81565b6103cc600f5481565b61039b6106c0366004612c6c565b6117c8565b6104466106d3366004612d26565b611926565b61039b6106e6366004612f13565b611abe565b6103cc611ad1565b61039b610701366004612d26565b611aed565b6103cc611b2a565b6103cc600e5481565b600254610413906001600160a01b031681565b61039b611beb565b61039b610740366004612d26565b611d0a565b61074d611eab565b6006546001600160a01b03908116908216036107985760405162461bcd60e51b8152602060048201526005602482015264085dd85b9d60da1b60448201526064015b60405180910390fd5b6002546001600160a01b03908116908216036107e05760405162461bcd60e51b81526020600482015260076024820152662173686172657360c81b604482015260640161078f565b606060005b81518110156108675781818151811061080057610800612f35565b60200260200101516001600160a01b0316836001600160a01b0316036108555760405162461bcd60e51b815260206004820152600a602482015269085c1c9bdd1958dd195960b21b604482015260640161078f565b8061085f81612f61565b9150506107e5565b506108ec610873611ed0565b6040516370a0823160e01b81523060048201526001600160a01b038516906370a0823190602401602060405180830381865afa1580156108b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108db9190612f7a565b6001600160a01b0385169190611f3e565b5050565b600080546108fd90612f93565b80601f016020809104026020016040519081016040528092919081815260200182805461092990612f93565b80156109765780601f1061094b57610100808354040283529160200191610976565b820191906000526020600020905b81548152906001019060200180831161095957829003601f168201915b505050505081565b60606011805461098d90612f93565b80601f01602080910402602001604051908101604052809291908181526020018280546109b990612f93565b8015610a065780601f106109db57610100808354040283529160200191610a06565b820191906000526020600020905b8154815290600101906020018083116109e957829003601f168201915b5050505050905090565b610a18611f6e565b600b805460ff19168215159081179091556040519081527f6ad28df1b554fa6cacd46ae82fa811748d53798feeb437ddf234bf3083953319906020015b60405180910390a150565b610a68611f6e565b6040516001600160a01b03821681527fc8db9c35f716b87af1fbb83f03c78646061931269301fd7ba6dcf189b4cdc2fc9060200160405180910390a1600180546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b6002546040516339ebf82360e01b815230600482015260009182916001600160a01b03909116906339ebf8239060240161012060405180830381865afa158015610b1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3e9190612fc7565b604001511180610b5557506000610b53611ad1565b115b905090565b610b62611f6e565b600c55565b600080610b72611ad1565b90506000610b7e611282565b905080821115610b8f579003919050565b60009250505090565b6002546000906001600160a01b03163314610bde5760405162461bcd60e51b8152602060048201526006602482015265085d985d5b1d60d21b604482015260640161078f565b6000610be983612010565b600654909350909150610c06906001600160a01b03163383611f3e565b50919050565b610c14612082565b60078190556040518181527fbb2c369a0355a34b02ab5fce0643150c87e1c8dfe7c918d465591879f57948b190602001610a55565b610c5161209e565b6002546040805163bf3759b560e01b81529051610cc5926001600160a01b03169163bf3759b59160048083019260209291908290030181865afa158015610c9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc09190612f7a565b6121f3565b565b610ccf61209e565b6000806000600260009054906101000a90046001600160a01b03166001600160a01b031663bf3759b56040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4b9190612f7a565b60095490915060009060ff1615610da8576000610d66612299565b905082811015610d8157610d7a8184613042565b9350610d96565b82811115610d9657610d938382613042565b94505b610da08484613042565b915050610db9565b610db1826123aa565b919550935090505b600b805460ff19169055604051600081527f6ad28df1b554fa6cacd46ae82fa811748d53798feeb437ddf234bf30839533199060200160405180910390a16002546040516339ebf82360e01b81523060048201526000916001600160a01b0316906339ebf8239060240161012060405180830381865afa158015610e41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e659190612fc7565b60c001516002546040516328766ebf60e21b81526004810188905260248101879052604481018590529192506001600160a01b03169063a1d9bafc906064016020604051808303816000875af1158015610ec3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee79190612f7a565b9250610ef2836121f3565b60015460ff168015610f13575060015461010090046001600160a01b031615155b15610fe55760015460405163c70fa00b60e01b815260048101879052602481018690526044810184905260648101859052608481018390526101009091046001600160a01b03169063c70fa00b9060a401602060405180830381865afa158015610f81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa59190613059565b610fe05760405162461bcd60e51b815260206004820152600c60248201526b216865616c7468636865636b60a01b604482015260640161078f565b611026565b604051600181527ff769f6bf659bbbdabf212d830720ce893eedc57f25ebb8e44edf5b300618a35b9060200160405180910390a16001805460ff1916811790555b6040805186815260208101869052908101839052606081018490527f4c0f499ffe6befa0ca7c826b0916cf87bea98de658013e76938489368d60d5099060800160405180910390a15050505050565b600b5461010090046001600160a01b03161561109057600080fd5b61109c86868686612428565b6110a68282612672565b505050505050565b6110b6612082565b6001600160a01b0381166110c957600080fd5b600580546001600160a01b0319166001600160a01b0383169081179091556040519081527f2f202ddb4a2e345f6323ed90f8fc8559d770a7abbbeee84dde8aca3351fe715490602001610a55565b61111f612082565b600061112c8284836130bc565b507f300e67d5a415b6d015a471d9c7b95dd58f3e8290af965e84e0f845de2996dda6828260405161115e92919061317c565b60405180910390a15050565b60105460009060ff1661117c57600080fd5b604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81523060601b601482018190526e5af43d82803e903d91602b57fd5bf360881b6028830152906037816000f0604051632e89876360e11b81529093506001600160a01b0384169150635d130ec6906111fd908b908b908b908b908b908b906004016131ab565b600060405180830381600087803b15801561121757600080fd5b505af115801561122b573d6000803e3d6000fd5b50506040516001600160a01b03851692507f783540fb4221a3238720dc7038937d0d79982bcf895274aa6ad179f82cf0d53c9150600090a2509695505050505050565b611276611f6e565b61127f816126ba565b50565b6002546040516339ebf82360e01b81523060048201526000916001600160a01b0316906339ebf8239060240161012060405180830381865afa1580156112cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f09190612fc7565b60c00151905090565b60095460009061010090046001600160a01b03166113175750600190565b600960019054906101000a90046001600160a01b03166001600160a01b03166334a9e75c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561136a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b559190613059565b611396611f6e565b60098054610100600160a81b0319166101006001600160a01b038416908102919091179091556040519081527f711be97287cb9ec921887b9be36e148e1a27c6b158547b22b9704ffc54447a0f90602001610a55565b6113f4611f6e565b60405181151581527ff769f6bf659bbbdabf212d830720ce893eedc57f25ebb8e44edf5b300618a35b9060200160405180910390a16001805460ff1916911515919091179055565b611444611f6e565b61271081106114955760405162461bcd60e51b815260206004820152601a60248201527f596f75722073697a6520697320746f6f206d7563682073697a65000000000000604482015260640161078f565b600f55565b600654604051632415d18360e11b81526001600160a01b0390911660048201526000907383d95e0d5f402511db06817aff3f9ea88224b030908290829063482ba30690602401602060405180830381865afa1580156114fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115219190612f7a565b9050600b60019054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611576573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159a9190612f7a565b6115a590600a6132df565b816115ae610b67565b6115b891906132eb565b6115c2919061330a565b9250505090565b6006546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a08231906024015b602060405180830381865afa158015611613573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b559190612f7a565b61163f612082565b6001600160a01b03811661165257600080fd5b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527f352ececae6d7d1e6d26bcf2c549dfd55be1637e9b22dc0cf3b71ddb36097a6b490602001610a55565b6002546001600160a01b031633146116b757600080fd5b6002546040805163fbfa77cf60e01b815290516001600160a01b039283169284169163fbfa77cf9160048083019260209291908290030181865afa158015611703573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611727919061332c565b6001600160a01b03161461173a57600080fd5b6117438161286b565b6006546040516370a0823160e01b815230600482015261127f9183916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611791573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b59190612f7a565b6006546001600160a01b03169190611f3e565b6117d06128f9565b6001600160a01b0381166117e357600080fd5b6002546004805460405163095ea7b360e01b81526001600160a01b0391821692810192909252600060248301529091169063095ea7b3906044016020604051808303816000875af115801561183c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118609190613059565b50600480546001600160a01b0319166001600160a01b03838116918217835560025460405163095ea7b360e01b8152938401929092526000196024840152169063095ea7b3906044016020604051808303816000875af11580156118c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ec9190613059565b506040516001600160a01b03821681527fafbb66abf8f3b719799940473a4052a3717cdd8e40fb6c8a3faadab316b1a06990602001610a55565b6000611930610acc565b61193c57506000919050565b600061194661149a565b9050600e5481111561195b5750600192915050565b6119636112f9565b6119705750600092915050565b600b5460ff16156119845750600192915050565b600d548111156119975750600192915050565b6002546040516339ebf82360e01b81523060048201526000916001600160a01b0316906339ebf8239060240161012060405180830381865afa1580156119e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a059190612fc7565b90506008548160a0015142611a1a9190613042565b1115611a2a575060019392505050565b600a54600260009054906101000a90046001600160a01b03166001600160a01b031663112c1f9b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa49190612f7a565b1115611ab4575060019392505050565b5060009392505050565b611ac6611f6e565b600d91909155600e55565b6000611adb611b2a565b611ae36115c9565b610b559190613349565b611af5612082565b60088190556040518181527f5430e11864ad7aa9775b07d12657fe52df9aa2ba734355bd8ef8747be2c800c590602001610a55565b600b546040516370a0823160e01b815230600482015260009173444443bae5bb8640677a8cdf94cb8879fec948ec9163d3d83fa69161010090046001600160a01b03169081906370a0823190602401602060405180830381865afa158015611b96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bba9190612f7a565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016115f6565b611bf3612932565b6009805460ff191660011790556002546040516339ebf82360e01b81523060048201526001600160a01b03909116906339ebf8239060240161012060405180830381865afa158015611c49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c6d9190612fc7565b6040015115611cdf57600260009054906101000a90046001600160a01b03166001600160a01b031663a0e4af9a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611cc657600080fd5b505af1158015611cda573d6000803e3d6000fd5b505050505b6040517f97e963041e952738788b9d4871d854d282065b8f90a464928d6528f2e9a4fd0b90600090a1565b611d12611f6e565b600a8190556040518181527fe5ef7832c564a10cbe7b4f1e01ac33a406cb63fcf430a97a9af8616d150af5f390602001610a55565b801580611dc15750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611d9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbf9190612f7a565b155b611e2c5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606482015260840161078f565b6040516001600160a01b038316602482015260448101829052611e8f90849063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261294e565b505050565b6060611ea38484600085612a20565b949350505050565b611eb3611ed0565b6001600160a01b0316336001600160a01b031614610cc557600080fd5b60025460408051635aa6e67560e01b815290516000926001600160a01b031691635aa6e6759160048083019260209291908290030181865afa158015611f1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b55919061332c565b6040516001600160a01b038316602482015260448101829052611e8f90849063a9059cbb60e01b90606401611e58565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fe5919061332c565b6001600160a01b0316336001600160a01b031614806120075750611eb3611ed0565b610cc557600080fd5b600080600061201d6115c9565b905083811061203157509192600092509050565b80840361203d816126ba565b60006120476115c9565b90508086111561207657600061205d8288613042565b9050819550600f54811015612070578094505b5061207a565b8594505b505050915091565b6003546001600160a01b03163314806120075750611eb3611ed0565b6005546001600160a01b03163314806120c157506003546001600160a01b031633145b806120e457506120cf611ed0565b6001600160a01b0316336001600160a01b0316145b806121765750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa15801561213d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612161919061332c565b6001600160a01b0316336001600160a01b0316145b806120075750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121cf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eb3919061332c565b60095460ff16156122015750565b600061220b6115c9565b905080156108ec57600b54600654612235916001600160a01b036101009091048116911683612afb565b600b60019054906101000a90046001600160a01b03166001600160a01b031663d0e30db06040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561228557600080fd5b505af11580156110a6573d6000803e3d6000fd5b600b546040516370a0823160e01b815230600482015260009182916101009091046001600160a01b0316906370a0823190602401602060405180830381865afa1580156122ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230e9190612f7a565b9050801561239c57600b54600c54604051631cc6d2f960e31b81526004810184905230602482015260448101919091526101009091046001600160a01b03169063e63697c8906064016020604051808303816000875af1158015612376573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061239a9190612f7a565b505b6123a46115c9565b91505090565b6000806000806123b8611ad1565b905060006123c4611282565b905080821061241957808203945085925060006123e18487613349565b905060006123ee82612010565b509050808211156124125780851061240c5780945060009650612412565b84810396505b505061241f565b81810393505b50509193909250565b6006546001600160a01b0316156124815760405162461bcd60e51b815260206004820152601c60248201527f537472617465677920616c726561647920696e697469616c697a656400000000604482015260640161078f565b600280546001600160a01b0319166001600160a01b03861690811790915560408051637e062a3560e11b8152905163fc0c546a916004808201926020929091908290030181865afa1580156124da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124fe919061332c565b600680546001600160a01b0319166001600160a01b0392909216918217905561252a9085600019611d47565b600380546001600160a01b038086166001600160a01b031992831617909255600480548584169083161781556005805485851693169290921790915562278d006008556002546040805163313ce56760e01b81529051919093169263313ce56792818101926020929091908290030181865afa1580156125ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d29190612f7a565b6125dd90600a6132df565b6125ea90620f42406132eb565b600a556002546004805460405163095ea7b360e01b81526001600160a01b039182169281019290925260001960248301529091169063095ea7b3906044016020604051808303816000875af1158015612647573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266b9190613059565b5050505050565b600b8054610100600160a81b0319166101006001600160a01b03851602179055601161269e8282613361565b505064012a05f200600d5550640ba43b7400600e55600a600f55565b806000036126c55750565b600b546040516370a0823160e01b815230600482015260009161010090046001600160a01b0316906370a0823190602401602060405180830381865afa158015612713573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127379190612f7a565b600b54604051632967214160e21b81526101009091046001600160a01b03166004820152602481018490529091506000906127d29073444443bae5bb8640677a8cdf94cb8879fec948ec9063a59c850490604401602060405180830381865afa1580156127a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127cc9190612f7a565b83612b9f565b9050806000036127e157505050565b600b54600c54604051631cc6d2f960e31b81526004810184905230602482015260448101919091526101009091046001600160a01b03169063e63697c8906064016020604051808303816000875af1158015612841573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128659190612f7a565b50505050565b600b546040516370a0823160e01b815230600482015261127f9183916101009091046001600160a01b0316906370a0823190602401602060405180830381865afa1580156128bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128e19190612f7a565b600b5461010090046001600160a01b03169190611f3e565b612901611ed0565b6001600160a01b0316336001600160a01b0316148061200757506003546001600160a01b03163314610cc557600080fd5b6003546001600160a01b03163314806120e457506120cf611ed0565b60006129a3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611e949092919063ffffffff16565b805190915015611e8f57808060200190518101906129c19190613059565b611e8f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161078f565b606082471015612a815760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161078f565b600080866001600160a01b03168587604051612a9d9190613421565b60006040518083038185875af1925050503d8060008114612ada576040519150601f19603f3d011682016040523d82523d6000602084013e612adf565b606091505b5091509150612af087838387612bb9565b979650505050505050565b604051636eb1769f60e11b81523060048201526001600160a01b03848116602483015282919084169063dd62ed3e90604401602060405180830381865afa158015612b4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6e9190612f7a565b1015611e8f57612b896001600160a01b038316846000611d47565b611e8f6001600160a01b03831684600019611d47565b6000818310612bae5781612bb0565b825b90505b92915050565b60608315612c28578251600003612c21576001600160a01b0385163b612c215760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161078f565b5081611ea3565b611ea38383815115612c3d5781518083602001fd5b8060405162461bcd60e51b815260040161078f9190612ce8565b6001600160a01b038116811461127f57600080fd5b600060208284031215612c7e57600080fd5b8135612c8981612c57565b9392505050565b60005b83811015612cab578181015183820152602001612c93565b838111156128655750506000910152565b60008151808452612cd4816020860160208601612c90565b601f01601f19169290920160200192915050565b602081526000612bb06020830184612cbc565b801515811461127f57600080fd5b600060208284031215612d1b57600080fd5b8135612c8981612cfb565b600060208284031215612d3857600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715612d7957612d79612d3f565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715612da857612da8612d3f565b604052919050565b60008060008060008060c08789031215612dc957600080fd5b8635612dd481612c57565b9550602087810135612de581612c57565b95506040880135612df581612c57565b94506060880135612e0581612c57565b93506080880135612e1581612c57565b925060a088013567ffffffffffffffff80821115612e3257600080fd5b818a0191508a601f830112612e4657600080fd5b813581811115612e5857612e58612d3f565b612e6a601f8201601f19168501612d7f565b91508082528b84828501011115612e8057600080fd5b80848401858401376000848284010152508093505050509295509295509295565b60008060208385031215612eb457600080fd5b823567ffffffffffffffff80821115612ecc57600080fd5b818501915085601f830112612ee057600080fd5b813581811115612eef57600080fd5b866020828501011115612f0157600080fd5b60209290920196919550909350505050565b60008060408385031215612f2657600080fd5b50508035926020909101359150565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612f7357612f73612f4b565b5060010190565b600060208284031215612f8c57600080fd5b5051919050565b600181811c90821680612fa757607f821691505b602082108103610c0657634e487b7160e01b600052602260045260246000fd5b60006101208284031215612fda57600080fd5b612fe2612d55565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b60008282101561305457613054612f4b565b500390565b60006020828403121561306b57600080fd5b8151612c8981612cfb565b601f821115611e8f57600081815260208120601f850160051c8101602086101561309d5750805b601f850160051c820191505b818110156110a6578281556001016130a9565b67ffffffffffffffff8311156130d4576130d4612d3f565b6130e8836130e28354612f93565b83613076565b6000601f84116001811461311c57600085156131045750838201355b600019600387901b1c1916600186901b17835561266b565b600083815260209020601f19861690835b8281101561314d578685013582556020948501946001909201910161312d565b508682101561316a5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b6001600160a01b0387811682528681166020830152858116604083015284811660608301528316608082015260c060a082018190526000906131ef90830184612cbc565b98975050505050505050565b600181815b8085111561323657816000190482111561321c5761321c612f4b565b8085161561322957918102915b93841c9390800290613200565b509250929050565b60008261324d57506001612bb3565b8161325a57506000612bb3565b8160018114613270576002811461327a57613296565b6001915050612bb3565b60ff84111561328b5761328b612f4b565b50506001821b612bb3565b5060208310610133831016604e8410600b84101617156132b9575081810a612bb3565b6132c383836131fb565b80600019048211156132d7576132d7612f4b565b029392505050565b6000612bb0838361323e565b600081600019048311821515161561330557613305612f4b565b500290565b60008261332757634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561333e57600080fd5b8151612c8981612c57565b6000821982111561335c5761335c612f4b565b500190565b815167ffffffffffffffff81111561337b5761337b612d3f565b61338f816133898454612f93565b84613076565b602080601f8311600181146133c457600084156133ac5750858301515b600019600386901b1c1916600185901b1785556110a6565b600085815260208120601f198616915b828110156133f3578886015182559484019460019091019084016133d4565b50858210156134115787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008251613433818460208701612c90565b919091019291505056fea264697066735822122036aa1d7c57341d491068eb52b81162d96db22a453d81893d0bf4e46d9779124664736f6c634300080f0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e537b5cc158eb71037d4125bdd7538421981e6aa0000000000000000000000008078198fc424986ae89ce4a910fc109587b6abf3000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000185374726174656779526f7574657256322d3343727970746f0000000000000000
-----Decoded View---------------
Arg [0] : _vault (address): 0xE537B5cc158EB71037D4125BDD7538421981E6AA
Arg [1] : _yVault (address): 0x8078198Fc424986ae89Ce4a910Fc109587b6aBF3
Arg [2] : _strategyName (string): StrategyRouterV2-3Crypto
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000e537b5cc158eb71037d4125bdd7538421981e6aa
Arg [1] : 0000000000000000000000008078198fc424986ae89ce4a910fc109587b6abf3
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000018
Arg [4] : 5374726174656779526f7574657256322d3343727970746f0000000000000000
Deployed Bytecode Sourcemap
1285:15429:8:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;36170:436:9;;;;;;:::i;:::-;;:::i;:::-;;6816:25;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;5362:99:8;;;:::i;2013:37::-;;;;;;;;;1299:25:10;;;1287:2;1272:18;2013:37:8;1153:177:10;17426:222:9;;;;;;:::i;:::-;;:::i;13207:159::-;;;;;;:::i;:::-;;:::i;8792:18::-;;;;;-1:-1:-1;;;;;8792:18:9;;;;;;-1:-1:-1;;;;;1882:32:10;;;1864:51;;1852:2;1837:18;8792::9;1704:217:10;8705:25:9;;;;;-1:-1:-1;;;;;8705:25:9;;;21300:146;;;:::i;:::-;;;2299:14:10;;2292:22;2274:41;;2262:2;2247:18;21300:146:9;2134:187:10;15536:98:8;;;;;;:::i;:::-;;:::i;7202:89:9:-;7270:14;;;;;;;;;;;;-1:-1:-1;;;7270:14:9;;;;7202:89;;9779:29;;;;;;6755:325:8;;;:::i;32588:507:9:-;;;;;;:::i;:::-;;:::i;1481:20:8:-;;;;;;;;-1:-1:-1;;;;;1481:20:8;;;15714:151:9;;;;;;:::i;:::-;;:::i;26365:167::-;;;:::i;30625:1729::-;;;:::i;9856:25::-;;;;;;;;;1616:22:8;;;;;;4632:364;;;;;;:::i;:::-;;:::i;25550:497:9:-;;;;;;:::i;:::-;-1:-1:-1;25623:4:9;;25550:497;6869:25;;;;;;;;;2516:29:8;;;;;;;;;14501:170:9;;;;;;:::i;:::-;;:::i;18439:168::-;;;;;;:::i;:::-;;:::i;12059:131:8:-;;;;;;:::i;9938:28:9:-;;;;;;;;-1:-1:-1;;;;;9938:28:9;;;3432:1194:8;;;;;;:::i;:::-;;:::i;10063:117::-;;;;;;:::i;:::-;;:::i;6047:131::-;;;:::i;29645:193:9:-;;;:::i;9632:29::-;;;;;;8736:22;;;;;-1:-1:-1;;;;;8736:22:9;;;17971:175;;;;;;:::i;:::-;;:::i;10100:35::-;;;;;;;;;10015:30;;;;;;13372:168;;;;;;:::i;:::-;;:::i;8764:21::-;;;;;-1:-1:-1;;;;;8764:21:9;;;15845:215:8;;;;;;:::i;:::-;;:::i;6900:26:9:-;;;;;;;;-1:-1:-1;;;;;6900:26:9;;;14602:475:8;;;:::i;6241:108::-;;;:::i;13764:198:9:-;;;;;;:::i;:::-;;:::i;33846:276::-;;;;;;:::i;:::-;;:::i;1793:102:8:-;;1852:42;1793:102;;2362:28;;;;;;14950:261:9;;;;;;:::i;:::-;;:::i;12779:1553:8:-;;;;;;:::i;:::-;;:::i;16441:271::-;;;;;;:::i;:::-;;:::i;5546:184::-;;;:::i;16368:151:9:-;;;;;;:::i;:::-;;:::i;6448:230:8:-;;;:::i;2204:37::-;;;;;;8678:21:9;;;;;-1:-1:-1;;;;;8678:21:9;;;34539:244;;;:::i;16854:187::-;;;;;;:::i;:::-;;:::i;36170:436::-;10444:17;:15;:17::i;:::-;36261:4:::1;::::0;-1:-1:-1;;;;;36261:4:9;;::::1;36243:23:::0;;::::1;::::0;36235:41:::1;;;::::0;-1:-1:-1;;;36235:41:9;;6375:2:10;36235:41:9::1;::::0;::::1;6357:21:10::0;6414:1;6394:18;;;6387:29;-1:-1:-1;;;6432:18:10;;;6425:35;6477:18;;36235:41:9::1;;;;;;;;;36312:5;::::0;-1:-1:-1;;;;;36312:5:9;;::::1;36294:24:::0;;::::1;::::0;36286:44:::1;;;::::0;-1:-1:-1;;;36286:44:9;;6708:2:10;36286:44:9::1;::::0;::::1;6690:21:10::0;6747:1;6727:18;;;6720:29;-1:-1:-1;;;6765:18:10;;;6758:37;6812:18;;36286:44:9::1;6506:330:10::0;36286:44:9::1;11454:20:8::0;36341:33:9::1;36404:102;36424:16;:23;36420:1;:27;36404:102;;;36472:16;36489:1;36472:19;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1::0;;;;;36462:29:9::1;:6;-1:-1:-1::0;;;;;36462:29:9::1;::::0;36454:52:::1;;;::::0;-1:-1:-1;;;36454:52:9;;7175:2:10;36454:52:9::1;::::0;::::1;7157:21:10::0;7214:2;7194:18;;;7187:30;-1:-1:-1;;;7233:18:10;;;7226:40;7283:18;;36454:52:9::1;6973:334:10::0;36454:52:9::1;36449:3:::0;::::1;::::0;::::1;:::i;:::-;;;;36404:102;;;;36517:82;36545:12;:10;:12::i;:::-;36559:39;::::0;-1:-1:-1;;;36559:39:9;;36592:4:::1;36559:39;::::0;::::1;1864:51:10::0;-1:-1:-1;;;;;36559:24:9;::::1;::::0;::::1;::::0;1837:18:10;;36559:39:9::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;36517:27:9;::::1;::::0;:82;:27:::1;:82::i;:::-;36225:381;36170:436:::0;:::o;6816:25::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;5362:99:8:-;5410:13;5442:12;5435:19;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5362:99;:::o;17426:222:9:-;10668:20;:18;:20::i;:::-;17530:23:::1;:50:::0;;-1:-1:-1;;17530:50:9::1;::::0;::::1;;::::0;;::::1;::::0;;;17595:46:::1;::::0;2274:41:10;;;17595:46:9::1;::::0;2262:2:10;2247:18;17595:46:9::1;;;;;;;;17426:222:::0;:::o;13207:159::-;10668:20;:18;:20::i;:::-;13295:28:::1;::::0;-1:-1:-1;;;;;1882:32:10;;1864:51;;13295:28:9::1;::::0;1852:2:10;1837:18;13295:28:9::1;;;;;;;13333:11;:26:::0;;-1:-1:-1;;;;;13333:26:9;;::::1;;;-1:-1:-1::0;;;;;;13333:26:9;;::::1;::::0;;;::::1;::::0;;13207:159::o;21300:146::-;21364:5;;:31;;-1:-1:-1;;;21364:31:9;;21389:4;21364:31;;;1864:51:10;21341:4:9;;;;-1:-1:-1;;;;;21364:5:9;;;;:16;;1837:18:10;;21364:31:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;;;:45;:75;;;;21438:1;21413:22;:20;:22::i;:::-;:26;21364:75;21357:82;;21300:146;:::o;15536:98:8:-;10668:20:9;:18;:20::i;:::-;15609:7:8::1;:18:::0;15536:98::o;6755:325::-;6804:15;6831:14;6848:22;:20;:22::i;:::-;6831:39;;6880:12;6895:17;:15;:17::i;:::-;6880:32;;6936:4;6927:6;:13;6923:151;;;6994:13;;;6755:325;-1:-1:-1;6755:325:8:o;6923:151::-;7062:1;7052:11;;6821:259;;6755:325;:::o;32588:507:9:-;32702:5;;32647:13;;-1:-1:-1;;;;;32702:5:9;32680:10;:28;32672:47;;;;-1:-1:-1;;;32672:47:9;;9149:2:10;32672:47:9;;;9131:21:10;9188:1;9168:18;;;9161:29;-1:-1:-1;;;9206:18:10;;;9199:36;9252:18;;32672:47:9;8947:329:10;32672:47:9;32803:19;32855:32;32873:13;32855:17;:32::i;:::-;32977:4;;32832:55;;-1:-1:-1;32832:55:9;;-1:-1:-1;32977:42:9;;-1:-1:-1;;;;;32977:4:9;32995:10;32832:55;32977:17;:42::i;:::-;32662:433;32588:507;;;:::o;15714:151::-;10195:17;:15;:17::i;:::-;15791:14:::1;:23:::0;;;15829:29:::1;::::0;1299:25:10;;;15829:29:9::1;::::0;1287:2:10;1272:18;15829:29:9::1;1153:177:10::0;26365:167:9;10591:14;:12;:14::i;:::-;26501:5:::1;::::0;:23:::1;::::0;;-1:-1:-1;;;26501:23:9;;;;26486:39:::1;::::0;-1:-1:-1;;;;;26501:5:9::1;::::0;:21:::1;::::0;:23:::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;:5;:23:::1;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;26486:14;:39::i;:::-;26365:167::o:0;30625:1729::-;10591:14;:12;:14::i;:::-;30675::::1;30703:12:::0;30729:23:::1;30755:5;;;;;;;;;-1:-1:-1::0;;;;;30755:5:9::1;-1:-1:-1::0;;;;;30755:21:9::1;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;30825:13;::::0;30729:49;;-1:-1:-1;30788:19:9::1;::::0;30825:13:::1;;30821:559;;;30905:19;30927:23;:21;:23::i;:::-;30905:45;;30982:15;30968:11;:29;30964:216;;;31024:29;31042:11:::0;31024:15;:29:::1;:::i;:::-;31017:36;;30964:216;;;31092:15;31078:11;:29;31074:106;;;31136:29;31150:15:::0;31136:11;:29:::1;:::i;:::-;31127:38;;31074:106;31207:22;31225:4:::0;31207:15;:22:::1;:::i;:::-;31193:36;;30840:400;30821:559;;;31339:30;31353:15;31339:13;:30::i;:::-;31309:60:::0;;-1:-1:-1;31309:60:9;-1:-1:-1;31309:60:9;-1:-1:-1;30821:559:9::1;31459:23;:31:::0;;-1:-1:-1;;31459:31:9::1;::::0;;31505:27:::1;::::0;-1:-1:-1;2274:41:10;;31505:27:9::1;::::0;2262:2:10;2247:18;31505:27:9::1;;;;;;;31744:5;::::0;:31:::1;::::0;-1:-1:-1;;;31744:31:9;;31769:4:::1;31744:31;::::0;::::1;1864:51:10::0;31724:17:9::1;::::0;-1:-1:-1;;;;;31744:5:9::1;::::0;:16:::1;::::0;1837:18:10;;31744:31:9::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;;::::0;31813:5:::1;::::0;:39:::1;::::0;-1:-1:-1;;;31813:39:9;;::::1;::::0;::::1;9613:25:10::0;;;9654:18;;;9647:34;;;9697:18;;;9690:34;;;31744:41:9;;-1:-1:-1;;;;;;31813:5:9::1;::::0;:12:::1;::::0;9586:18:10;;31813:39:9::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;31795:57;;31925:31;31940:15;31925:14;:31::i;:::-;32008:13;::::0;::::1;;:42:::0;::::1;;;-1:-1:-1::0;32025:11:9::1;::::0;::::1;::::0;::::1;-1:-1:-1::0;;;;;32025:11:9::1;:25:::0;::::1;32008:42;32004:275;;;32086:11;::::0;32074:85:::1;::::0;-1:-1:-1;;;32074:85:9;;::::1;::::0;::::1;9994:25:10::0;;;10035:18;;;10028:34;;;10078:18;;;10071:34;;;10121:18;;;10114:34;;;10164:19;;;10157:35;;;32086:11:9::1;::::0;;::::1;-1:-1:-1::0;;;;;32086:11:9::1;::::0;32074:30:::1;::::0;9966:19:10;;32074:85:9::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;32066:110;;;::::0;-1:-1:-1;;;32066:110:9;;10655:2:10;32066:110:9::1;::::0;::::1;10637:21:10::0;10694:2;10674:18;;;10667:30;-1:-1:-1;;;10713:18:10;;;10706:42;10765:18;;32066:110:9::1;10453:336:10::0;32066:110:9::1;32004:275;;;32212:22;::::0;32229:4:::1;2274:41:10::0;;32212:22:9::1;::::0;2262:2:10;2247:18;32212:22:9::1;;;;;;;32264:4;32248:20:::0;;-1:-1:-1;;32248:20:9::1;::::0;::::1;::::0;;32004:275:::1;32294:53;::::0;;11025:25:10;;;11081:2;11066:18;;11059:34;;;11109:18;;;11102:34;;;11167:2;11152:18;;11145:34;;;32294:53:9::1;::::0;11012:3:10;10997:19;32294:53:9::1;;;;;;;30665:1689;;;;;30625:1729::o:0;4632:364:8:-;4857:6;;;;;-1:-1:-1;;;;;4857:6:8;4849:29;4841:38;;;;;;4889:51;4901:6;4909:11;4922:8;4932:7;4889:11;:51::i;:::-;4950:39;4966:7;4975:13;4950:15;:39::i;:::-;4632:364;;;;;;:::o;14501:170:9:-;10195:17;:15;:17::i;:::-;-1:-1:-1;;;;;14579:21:9;::::1;14571:30;;;::::0;::::1;;14611:6;:16:::0;;-1:-1:-1;;;;;;14611:16:9::1;-1:-1:-1::0;;;;;14611:16:9;::::1;::::0;;::::1;::::0;;;14642:22:::1;::::0;1864:51:10;;;14642:22:9::1;::::0;1852:2:10;1837:18;14642:22:9::1;1704:217:10::0;18439:168:9;10195:17;:15;:17::i;:::-;18527:11:::1;:26;18541:12:::0;;18527:11;:26:::1;:::i;:::-;;18568:32;18587:12;;18568:32;;;;;;;:::i;:::-;;;;;;;;18439:168:::0;;:::o;3432:1194:8:-;3698:10;;3659:19;;3698:10;;3690:19;;;;;;3961:4;3955:11;-1:-1:-1;;;3979:132:8;;3865:4;3849:22;;4147:4;4131:21;;4124:43;;;-1:-1:-1;;;4220:4:8;4204:21;;4180:143;3849:22;4373:4;3955:11;3826:20;4351:27;4398:186;;-1:-1:-1;;;4398:186:8;;4336:42;;-1:-1:-1;;;;;;4398:40:8;;;-1:-1:-1;4398:40:8;;:186;;4452:6;;4472:11;;4497:8;;4519:7;;4540;;4561:13;;4398:186;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4600:19:8;;-1:-1:-1;;;;;4600:19:8;;;-1:-1:-1;4600:19:8;;-1:-1:-1;4600:19:8;;;3680:946;3432:1194;;;;;;;;:::o;10063:117::-;10668:20:9;:18;:20::i;:::-;10145:28:8::1;10165:7;10145:19;:28::i;:::-;10063:117:::0;:::o;6047:131::-;6130:5;;:31;;-1:-1:-1;;;6130:31:8;;6155:4;6130:31;;;1864:51:10;6104:7:8;;-1:-1:-1;;;;;6130:5:8;;:16;;1837:18:10;;6130:31:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;;;6123:48;;6047:131;:::o;29645:193:9:-;29717:13;;29697:4;;29717:13;;;-1:-1:-1;;;;;29717:13:9;29713:118;;-1:-1:-1;29753:4:9;;29645:193::o;29713:118::-;29788:13;;;;;;;;;-1:-1:-1;;;;;29788:13:9;-1:-1:-1;;;;;29779:50:9;;:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;17971:175::-;10668:20;:18;:20::i;:::-;18058:13:::1;:30:::0;;-1:-1:-1;;;;;;18058:30:9::1;;-1:-1:-1::0;;;;;18058:30:9;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;18103:36:::1;::::0;1864:51:10;;;18103:36:9::1;::::0;1852:2:10;1837:18;18103:36:9::1;1704:217:10::0;13372:168:9;10668:20;:18;:20::i;:::-;13461:32:::1;::::0;2299:14:10;;2292:22;2274:41;;13461:32:9::1;::::0;2262:2:10;2247:18;13461:32:9::1;;;;;;;13503:13;:30:::0;;-1:-1:-1;;13503:30:9::1;::::0;::::1;;::::0;;;::::1;::::0;;13372:168::o;15845:215:8:-;10668:20:9;:18;:20::i;:::-;15977:5:8::1;15960:14;:22;15952:61;;;::::0;-1:-1:-1;;;15952:61:8;;14512:2:10;15952:61:8::1;::::0;::::1;14494:21:10::0;14551:2;14531:18;;;14524:30;14590:28;14570:18;;;14563:56;14636:18;;15952:61:8::1;14310:350:10::0;15952:61:8::1;16023:13;:30:::0;15845:215::o;14602:475::-;14873:4;;14829:50;;-1:-1:-1;;;14829:50:8;;-1:-1:-1;;;;;14873:4:8;;;14829:50;;;1864:51:10;14656:7:8;;14717:42;;14656:7;;14717:42;;14829:35;;1837:18:10;;14829:50:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;14791:88;;15052:6;;;;;;;;;-1:-1:-1;;;;;15052:6:8;-1:-1:-1;;;;;15052:15:8;;:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;15048:21;;:2;:21;:::i;:::-;15028:15;15007:18;:16;:18::i;:::-;:36;;;;:::i;:::-;15006:64;;;;:::i;:::-;14999:71;;;;14602:475;:::o;6241:108::-;6313:4;;:29;;-1:-1:-1;;;6313:29:8;;6336:4;6313:29;;;1864:51:10;6287:7:8;;-1:-1:-1;;;;;6313:4:8;;:14;;1837:18:10;;6313:29:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;13764:198:9:-;10195:17;:15;:17::i;:::-;-1:-1:-1;;;;;13850:25:9;::::1;13842:34;;;::::0;::::1;;13886:10;:24:::0;;-1:-1:-1;;;;;;13886:24:9::1;-1:-1:-1::0;;;;;13886:24:9;::::1;::::0;;::::1;::::0;;;13925:30:::1;::::0;1864:51:10;;;13925:30:9::1;::::0;1852:2:10;1837:18;13925:30:9::1;1704:217:10::0;33846:276:9;33934:5;;-1:-1:-1;;;;;33934:5:9;33912:10;:28;33904:37;;;;;;33997:5;;33959:34;;;-1:-1:-1;;;33959:34:9;;;;-1:-1:-1;;;;;33997:5:9;;;;33959:32;;;;;:34;;;;;;;;;;;;;;:32;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;33959:43:9;;33951:52;;;;;;34013:30;34030:12;34013:16;:30::i;:::-;34085:4;;:29;;-1:-1:-1;;;34085:29:9;;34108:4;34085:29;;;1864:51:10;34053:62:9;;34071:12;;-1:-1:-1;;;;;34085:4:9;;;;:14;;1837:18:10;;34085:29:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;34053:4;;-1:-1:-1;;;;;34053:4:9;;:62;:17;:62::i;14950:261::-;10519:15;:13;:15::i;:::-;-1:-1:-1;;;;;15028:22:9;::::1;15020:31;;;::::0;::::1;;15061:5;::::0;15075:7:::1;::::0;;15061:25:::1;::::0;-1:-1:-1;;;15061:25:9;;-1:-1:-1;;;;;15075:7:9;;::::1;15061:25:::0;;::::1;16889:51:10::0;;;;15061:5:9::1;16956:18:10::0;;;16949:34;15061:5:9;;::::1;::::0;:13:::1;::::0;16862:18:10;;15061:25:9::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;15096:7:9::1;:18:::0;;-1:-1:-1;;;;;;15096:18:9::1;-1:-1:-1::0;;;;;15096:18:9;;::::1;::::0;;::::1;::::0;;15124:5:::1;::::0;:41:::1;::::0;-1:-1:-1;;;15124:41:9;;;;::::1;16889:51:10::0;;;;-1:-1:-1;;16956:18:10;;;16949:34;15124:5:9::1;::::0;:13:::1;::::0;16862:18:10;;15124:41:9::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;15180:24:9::1;::::0;-1:-1:-1;;;;;1882:32:10;;1864:51;;15180:24:9::1;::::0;1852:2:10;1837:18;15180:24:9::1;1704:217:10::0;12779:1553:8;12888:4;13046:10;:8;:10::i;:::-;13041:54;;-1:-1:-1;13079:5:8;;12779:1553;-1:-1:-1;12779:1553:8:o;13041:54::-;13202:23;13228;:21;:23::i;:::-;13202:49;;13283:22;;13265:15;:40;13261:82;;;-1:-1:-1;13328:4:8;;12779:1553;-1:-1:-1;;12779:1553:8:o;13261:82::-;13452:21;:19;:21::i;:::-;13447:65;;-1:-1:-1;13496:5:8;;12779:1553;-1:-1:-1;;12779:1553:8:o;13447:65::-;13617:23;;;;13613:65;;;-1:-1:-1;13663:4:8;;12779:1553;-1:-1:-1;;12779:1553:8:o;13613:65::-;13810:22;;13792:15;:40;13788:82;;;-1:-1:-1;13855:4:8;;12779:1553;-1:-1:-1;;12779:1553:8:o;13788:82::-;13911:5;;:31;;-1:-1:-1;;;13911:31:8;;13936:4;13911:31;;;1864:51:10;13880:28:8;;-1:-1:-1;;;;;13911:5:8;;:16;;1837:18:10;;13911:31:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;13880:62;;14061:14;;14041:6;:17;;;14023:15;:35;;;;:::i;:::-;:52;14019:94;;;-1:-1:-1;14098:4:8;;12779:1553;-1:-1:-1;;;12779:1553:8:o;14019:94::-;14211:15;;14185:5;;;;;;;;;-1:-1:-1;;;;;14185:5:8;-1:-1:-1;;;;;14185:21:8;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;14181:83;;;-1:-1:-1;14249:4:8;;12779:1553;-1:-1:-1;;;12779:1553:8:o;14181:83::-;-1:-1:-1;14320:5:8;;12779:1553;-1:-1:-1;;;12779:1553:8:o;16441:271::-;10668:20:9;:18;:20::i;:::-;16599:22:8::1;:48:::0;;;;16657:22:::1;:48:::0;16441:271::o;5546:184::-;5656:7;5704:19;:17;:19::i;:::-;5686:15;:13;:15::i;:::-;:37;;;;:::i;16368:151:9:-;10195:17;:15;:17::i;:::-;16445:14:::1;:23:::0;;;16483:29:::1;::::0;1299:25:10;;;16483:29:9::1;::::0;1287:2:10;1272:18;16483:29:9::1;1153:177:10::0;6448:230:8;6601:6;;6626:31;;-1:-1:-1;;;6626:31:8;;6651:4;6626:31;;;1864:51:10;-1:-1:-1;;1852:42:8;;6544:31;;6601:6;;;-1:-1:-1;;;;;6601:6:8;;;;6626:16;;1837:18:10;;6626:31:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6544:127;;-1:-1:-1;;;;;;6544:127:8;;;;;;;-1:-1:-1;;;;;16907:32:10;;;6544:127:8;;;16889:51:10;16956:18;;;16949:34;16862:18;;6544:127:8;16707:282:10;34539:244:9;10281:26;:24;:26::i;:::-;34610:13:::1;:20:::0;;-1:-1:-1;;34610:20:9::1;34626:4;34610:20;::::0;;34644:5:::1;::::0;:31:::1;::::0;-1:-1:-1;;;34644:31:9;;34669:4:::1;34644:31;::::0;::::1;1864:51:10::0;-1:-1:-1;;;;;34644:5:9;;::::1;::::0;:16:::1;::::0;1837:18:10;;34644:31:9::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;;::::0;:46;34640:99:::1;;34706:5;;;;;;;;;-1:-1:-1::0;;;;;34706:5:9::1;-1:-1:-1::0;;;;;34706:20:9::1;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;34640:99;34754:22;::::0;::::1;::::0;;;::::1;34539:244::o:0;16854:187::-;10668:20;:18;:20::i;:::-;16945:15:::1;:34:::0;;;16994:40:::1;::::0;1299:25:10;;;16994:40:9::1;::::0;1287:2:10;1272:18;16994:40:9::1;1153:177:10::0;1475:603:4;1830:10;;;1829:62;;-1:-1:-1;1846:39:4;;-1:-1:-1;;;1846:39:4;;1870:4;1846:39;;;17618:34:10;-1:-1:-1;;;;;17688:15:10;;;17668:18;;;17661:43;1846:15:4;;;;;17553:18:10;;1846:39:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;1829:62;1808:163;;;;-1:-1:-1;;;1808:163:4;;17917:2:10;1808:163:4;;;17899:21:10;17956:2;17936:18;;;17929:30;17995:34;17975:18;;;17968:62;-1:-1:-1;;;18046:18:10;;;18039:52;18108:19;;1808:163:4;17715:418:10;1808:163:4;2008:62;;-1:-1:-1;;;;;16907:32:10;;2008:62:4;;;16889:51:10;16956:18;;;16949:34;;;1981:90:4;;2001:5;;-1:-1:-1;;;2031:22:4;16862:18:10;;2008:62:4;;;;-1:-1:-1;;2008:62:4;;;;;;;;;;;;;;-1:-1:-1;;;;;2008:62:4;-1:-1:-1;;;;;;2008:62:4;;;;;;;;;;1981:19;:90::i;:::-;1475:603;;;:::o;3873:223:5:-;4006:12;4037:52;4059:6;4067:4;4073:1;4076:12;4037:21;:52::i;:::-;4030:59;3873:223;-1:-1:-1;;;;3873:223:5:o;11127:88:9:-;11195:12;:10;:12::i;:::-;-1:-1:-1;;;;;11181:26:9;:10;-1:-1:-1;;;;;11181:26:9;;11173:35;;;;;18755:96;18826:5;;:18;;;-1:-1:-1;;;18826:18:9;;;;18800:7;;-1:-1:-1;;;;;18826:5:9;;:16;;:18;;;;;;;;;;;;;;:5;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;763:205:4:-;902:58;;-1:-1:-1;;;;;16907:32:10;;902:58:4;;;16889:51:10;16956:18;;;16949:34;;;875:86:4;;895:5;;-1:-1:-1;;;925:23:4;16862:18:10;;902:58:4;16707:282:10;11640:127:9;11711:5;;;;;;;;;-1:-1:-1;;;;;11711:5:9;-1:-1:-1;;;;;11711:16:9;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;11697:32:9;:10;-1:-1:-1;;;;;11697:32:9;;:62;;;;11747:12;:10;:12::i;11697:62::-;11689:71;;;;;8854:1007:8;8971:25;8998:13;9027:15;9045;:13;:15::i;:::-;9027:33;;9085:13;9074:7;:24;9070:80;;-1:-1:-1;9122:13:8;;9137:1;;-1:-1:-1;8854:1007:8;-1:-1:-1;8854:1007:8:o;9070:80::-;9225:23;;;9311:31;9225:23;9311:19;:31::i;:::-;9353:17;9373:15;:13;:15::i;:::-;9353:35;;9588:9;9572:13;:25;9568:287;;;9613:12;9628:25;9644:9;9628:13;:25;:::i;:::-;9613:40;;9687:9;9667:29;;9721:13;;9714:4;:20;9710:71;;;9762:4;9754:12;;9710:71;9599:192;9568:287;;;9831:13;9811:33;;9568:287;9017:844;;;8854:1007;;;:::o;10712:116:9:-;10780:10;;-1:-1:-1;;;;;10780:10:9;10766;:24;;:54;;;10808:12;:10;:12::i;11341:293::-;11419:6;;-1:-1:-1;;;;;11419:6:9;11405:10;:20;;:64;;-1:-1:-1;11459:10:9;;-1:-1:-1;;;;;11459:10:9;11445;:24;11405:64;:110;;;;11503:12;:10;:12::i;:::-;-1:-1:-1;;;;;11489:26:9;:10;-1:-1:-1;;;;;11489:26:9;;11405:110;:160;;;;11549:5;;;;;;;;;-1:-1:-1;;;;;11549:5:9;-1:-1:-1;;;;;11549:14:9;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;11535:30:9;:10;-1:-1:-1;;;;;11535:30:9;;11405:160;:212;;;;11599:5;;;;;;;;;-1:-1:-1;;;;;11599:5:9;-1:-1:-1;;;;;11599:16:9;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;8497:351:8:-;8615:13;;;;8611:50;;;8497:351;:::o;8611:50::-;8671:15;8689;:13;:15::i;:::-;8671:33;-1:-1:-1;8718:11:8;;8714:128;;8769:6;;8786:4;;8745:56;;-1:-1:-1;;;;;8769:6:8;;;;;;;8786:4;8793:7;8745:15;:56::i;:::-;8815:6;;;;;;;;;-1:-1:-1;;;;;8815:6:8;-1:-1:-1;;;;;8815:14:8;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10699:445;10919:6;;:31;;-1:-1:-1;;;10919:31:8;;10944:4;10919:31;;;1864:51:10;10799:20:8;;;;10919:6;;;;-1:-1:-1;;;;;10919:6:8;;:16;;1837:18:10;;10919:31:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10891:59;-1:-1:-1;10964:21:8;;10960:110;;11001:6;;11051:7;;11001:58;;-1:-1:-1;;;11001:58:8;;;;;18596:25:10;;;11044:4:8;18637:18:10;;;18630:60;18706:18;;;18699:34;;;;11001:6:8;;;;-1:-1:-1;;;;;11001:6:8;;:15;;18569:18:10;;11001:58:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;10960:110;11122:15;:13;:15::i;:::-;11115:22;;;10699:445;:::o;7143:1348::-;7272:15;7301:13;7328:20;7461:14;7478:22;:20;:22::i;:::-;7461:39;;7510:12;7525:17;:15;:17::i;:::-;7510:32;;7637:4;7627:6;:14;7623:862;;7695:13;;;;-1:-1:-1;7751:16:8;;-1:-1:-1;7782:14:8;7799:22;7751:16;7695:13;7799:22;:::i;:::-;7782:39;;7891:13;7910:25;7928:6;7910:17;:25::i;:::-;7890:45;;;7963:5;7954:6;:14;7950:308;;;8008:5;7992:12;:21;7988:256;;8052:5;8037:20;;8089:1;8079:11;;7988:256;;;8191:12;8183:5;:20;8173:30;;7988:256;7643:625;;7623:862;;;8454:6;8447:4;:13;8439:21;;7623:862;7363:1128;;7143:1348;;;;;:::o;12423:778:9:-;12589:4;;-1:-1:-1;;;;;12589:4:9;12581:27;12573:68;;;;-1:-1:-1;;;12573:68:9;;18946:2:10;12573:68:9;;;18928:21:10;18985:2;18965:18;;;18958:30;19024;19004:18;;;18997:58;19072:18;;12573:68:9;18744:352:10;12573:68:9;12652:5;:24;;-1:-1:-1;;;;;;12652:24:9;-1:-1:-1;;;;;12652:24:9;;;;;;;;12700:13;;;-1:-1:-1;;;12700:13:9;;;;:11;;:13;;;;;;;;;;;;;;;12652:24;12700:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;12686:4;:28;;-1:-1:-1;;;;;;12686:28:9;-1:-1:-1;;;;;12686:28:9;;;;;;;;;12724:43;;12741:6;-1:-1:-1;;12724:16:9;:43::i;:::-;12825:10;:24;;-1:-1:-1;;;;;12825:24:9;;;-1:-1:-1;;;;;;12825:24:9;;;;;;;12859:7;:18;;;;;;;;;;;12887:6;:16;;;;;;;;;;;;;;12963:7;12946:14;:24;13014:5;;:16;;;-1:-1:-1;;;13014:16:9;;;;:5;;;;;:14;;:16;;;;;;;;;;;;;;:5;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;13010:20;;:2;:20;:::i;:::-;12998:32;;:9;:32;:::i;:::-;12980:15;:50;13123:5;;13137:7;;;13123:41;;-1:-1:-1;;;13123:41:9;;-1:-1:-1;;;;;13137:7:9;;;13123:41;;;16889:51:10;;;;-1:-1:-1;;16956:18:10;;;16949:34;13123:5:9;;;;:13;;16862:18:10;;13123:41:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;12423:778;;;;:::o;5002:284:8:-;5104:6;:24;;-1:-1:-1;;;;;;5104:24:8;;-1:-1:-1;;;;;5104:24:8;;;;;;5138:12;:28;5153:13;5138:12;:28;:::i;:::-;-1:-1:-1;;5201:7:8;5176:22;:32;-1:-1:-1;5243:8:8;5218:22;:33;5277:2;5261:13;:18;5002:284::o;10186:507::-;10255:7;10266:1;10255:12;10251:49;;10186:507;:::o;10251:49::-;10338:6;;:31;;-1:-1:-1;;;10338:31:8;;10363:4;10338:31;;;1864:51:10;10310:25:8;;10338:6;;;-1:-1:-1;;;;;10338:6:8;;:16;;1837:18:10;;10338:31:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10484:6;;10444:57;;-1:-1:-1;;;10444:57:8;;10484:6;;;;-1:-1:-1;;;;;10484:6:8;10444:57;;;16889:51:10;16956:18;;;16949:34;;;10310:59:8;;-1:-1:-1;;;10418:132:8;;1852:42;;10444:31;;16862:18:10;;10444:57:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10519:17;10418:8;:132::i;:::-;10379:171;;10565:16;10585:1;10565:21;10561:58;;10602:7;;10186:507;:::o;10561:58::-;10629:6;;10678:7;;10629:57;;-1:-1:-1;;;10629:57:8;;;;;18596:25:10;;;10671:4:8;18637:18:10;;;18630:60;18706:18;;;18699:34;;;;10629:6:8;;;;-1:-1:-1;;;;;10629:6:8;;:15;;18569:18:10;;10629:57:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;10241:452;;10186:507;:::o;11150:207::-;11308:6;;11301:39;;-1:-1:-1;;;11301:39:8;;11334:4;11301:39;;;1864:51:10;11234:116:8;;11275:12;;11308:6;;;;-1:-1:-1;;;;;11308:6:8;;11301:24;;1837:18:10;;11301:39:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11241:6;;;;;-1:-1:-1;;;;;11241:6:8;;;11234:27;:116::i;11221:114:9:-;11287:12;:10;:12::i;:::-;-1:-1:-1;;;;;11273:26:9;:10;-1:-1:-1;;;;;11273:26:9;;:54;;;-1:-1:-1;11317:10:9;;-1:-1:-1;;;;;11317:10:9;11303;:24;11265:63;;;;;10834:195;10911:10;;-1:-1:-1;;;;;10911:10:9;10897;:24;;:54;;;10939:12;:10;:12::i;3747:706:4:-;4166:23;4192:69;4220:4;4192:69;;;;;;;;;;;;;;;;;4200:5;-1:-1:-1;;;;;4192:27:4;;;:69;;;;;:::i;:::-;4275:17;;4166:95;;-1:-1:-1;4275:21:4;4271:176;;4370:10;4359:30;;;;;;;;;;;;:::i;:::-;4351:85;;;;-1:-1:-1;;;4351:85:4;;20660:2:10;4351:85:4;;;20642:21:10;20699:2;20679:18;;;20672:30;20738:34;20718:18;;;20711:62;-1:-1:-1;;;20789:18:10;;;20782:40;20839:19;;4351:85:4;20458:406:10;4960:446:5;5125:12;5182:5;5157:21;:30;;5149:81;;;;-1:-1:-1;;;5149:81:5;;21071:2:10;5149:81:5;;;21053:21:10;21110:2;21090:18;;;21083:30;21149:34;21129:18;;;21122:62;-1:-1:-1;;;21200:18:10;;;21193:36;21246:19;;5149:81:5;20869:402:10;5149:81:5;5241:12;5255:23;5282:6;-1:-1:-1;;;;;5282:11:5;5301:5;5308:4;5282:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5240:73;;;;5330:69;5357:6;5365:7;5374:10;5386:12;5330:26;:69::i;:::-;5323:76;4960:446;-1:-1:-1;;;;;;;4960:446:5:o;11488:333:8:-;11618:50;;-1:-1:-1;;;11618:50:8;;11651:4;11618:50;;;17618:34:10;-1:-1:-1;;;;;17688:15:10;;;17668:18;;;17661:43;11671:7:8;;11618:24;;;;;;17553:18:10;;11618:50:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:60;11614:201;;;11694:40;-1:-1:-1;;;;;11694:26:8;;11721:9;11732:1;11694:26;:40::i;:::-;11748:56;-1:-1:-1;;;;;11748:26:8;;11775:9;-1:-1:-1;;11748:26:8;:56::i;588:104:7:-;646:7;676:1;672;:5;:13;;684:1;672:13;;;680:1;672:13;665:20;;588:104;;;;;:::o;7466:628:5:-;7646:12;7674:7;7670:418;;;7701:10;:17;7722:1;7701:22;7697:286;;-1:-1:-1;;;;;1465:19:5;;;7908:60;;;;-1:-1:-1;;;7908:60:5;;21757:2:10;7908:60:5;;;21739:21:10;21796:2;21776:18;;;21769:30;21835:31;21815:18;;;21808:59;21884:18;;7908:60:5;21555:353:10;7908:60:5;-1:-1:-1;8003:10:5;7996:17;;7670:418;8044:33;8052:10;8064:12;8775:17;;:21;8771:379;;9003:10;8997:17;9059:15;9046:10;9042:2;9038:19;9031:44;8771:379;9126:12;9119:20;;-1:-1:-1;;;9119:20:5;;;;;;;;:::i;14:131:10:-;-1:-1:-1;;;;;89:31:10;;79:42;;69:70;;135:1;132;125:12;150:247;209:6;262:2;250:9;241:7;237:23;233:32;230:52;;;278:1;275;268:12;230:52;317:9;304:23;336:31;361:5;336:31;:::i;:::-;386:5;150:247;-1:-1:-1;;;150:247:10:o;402:258::-;474:1;484:113;498:6;495:1;492:13;484:113;;;574:11;;;568:18;555:11;;;548:39;520:2;513:10;484:113;;;615:6;612:1;609:13;606:48;;;-1:-1:-1;;650:1:10;632:16;;625:27;402:258::o;665:::-;707:3;745:5;739:12;772:6;767:3;760:19;788:63;844:6;837:4;832:3;828:14;821:4;814:5;810:16;788:63;:::i;:::-;905:2;884:15;-1:-1:-1;;880:29:10;871:39;;;;912:4;867:50;;665:258;-1:-1:-1;;665:258:10:o;928:220::-;1077:2;1066:9;1059:21;1040:4;1097:45;1138:2;1127:9;1123:18;1115:6;1097:45;:::i;1335:118::-;1421:5;1414:13;1407:21;1400:5;1397:32;1387:60;;1443:1;1440;1433:12;1458:241;1514:6;1567:2;1555:9;1546:7;1542:23;1538:32;1535:52;;;1583:1;1580;1573:12;1535:52;1622:9;1609:23;1641:28;1663:5;1641:28;:::i;2326:180::-;2385:6;2438:2;2426:9;2417:7;2413:23;2409:32;2406:52;;;2454:1;2451;2444:12;2406:52;-1:-1:-1;2477:23:10;;2326:180;-1:-1:-1;2326:180:10:o;2734:127::-;2795:10;2790:3;2786:20;2783:1;2776:31;2826:4;2823:1;2816:15;2850:4;2847:1;2840:15;2866:252;2938:2;2932:9;2980:3;2968:16;;3014:18;2999:34;;3035:22;;;2996:62;2993:88;;;3061:18;;:::i;:::-;3097:2;3090:22;2866:252;:::o;3123:275::-;3194:2;3188:9;3259:2;3240:13;;-1:-1:-1;;3236:27:10;3224:40;;3294:18;3279:34;;3315:22;;;3276:62;3273:88;;;3341:18;;:::i;:::-;3377:2;3370:22;3123:275;;-1:-1:-1;3123:275:10:o;3403:1466::-;3517:6;3525;3533;3541;3549;3557;3610:3;3598:9;3589:7;3585:23;3581:33;3578:53;;;3627:1;3624;3617:12;3578:53;3666:9;3653:23;3685:31;3710:5;3685:31;:::i;:::-;3735:5;-1:-1:-1;3759:2:10;3798:18;;;3785:32;3826:33;3785:32;3826:33;:::i;:::-;3878:7;-1:-1:-1;3937:2:10;3922:18;;3909:32;3950:33;3909:32;3950:33;:::i;:::-;4002:7;-1:-1:-1;4061:2:10;4046:18;;4033:32;4074:33;4033:32;4074:33;:::i;:::-;4126:7;-1:-1:-1;4185:3:10;4170:19;;4157:33;4199;4157;4199;:::i;:::-;4251:7;-1:-1:-1;4309:3:10;4294:19;;4281:33;4333:18;4363:14;;;4360:34;;;4390:1;4387;4380:12;4360:34;4428:6;4417:9;4413:22;4403:32;;4473:7;4466:4;4462:2;4458:13;4454:27;4444:55;;4495:1;4492;4485:12;4444:55;4531:2;4518:16;4553:2;4549;4546:10;4543:36;;;4559:18;;:::i;:::-;4601:53;4644:2;4625:13;;-1:-1:-1;;4621:27:10;4617:36;;4601:53;:::i;:::-;4588:66;;4677:2;4670:5;4663:17;4717:7;4712:2;4707;4703;4699:11;4695:20;4692:33;4689:53;;;4738:1;4735;4728:12;4689:53;4793:2;4788;4784;4780:11;4775:2;4768:5;4764:14;4751:45;4837:1;4832:2;4827;4820:5;4816:14;4812:23;4805:34;;4858:5;4848:15;;;;;3403:1466;;;;;;;;:::o;4874:592::-;4945:6;4953;5006:2;4994:9;4985:7;4981:23;4977:32;4974:52;;;5022:1;5019;5012:12;4974:52;5062:9;5049:23;5091:18;5132:2;5124:6;5121:14;5118:34;;;5148:1;5145;5138:12;5118:34;5186:6;5175:9;5171:22;5161:32;;5231:7;5224:4;5220:2;5216:13;5212:27;5202:55;;5253:1;5250;5243:12;5202:55;5293:2;5280:16;5319:2;5311:6;5308:14;5305:34;;;5335:1;5332;5325:12;5305:34;5380:7;5375:2;5366:6;5362:2;5358:15;5354:24;5351:37;5348:57;;;5401:1;5398;5391:12;5348:57;5432:2;5424:11;;;;;5454:6;;-1:-1:-1;4874:592:10;;-1:-1:-1;;;;4874:592:10:o;5695:248::-;5763:6;5771;5824:2;5812:9;5803:7;5799:23;5795:32;5792:52;;;5840:1;5837;5830:12;5792:52;-1:-1:-1;;5863:23:10;;;5933:2;5918:18;;;5905:32;;-1:-1:-1;5695:248:10:o;6841:127::-;6902:10;6897:3;6893:20;6890:1;6883:31;6933:4;6930:1;6923:15;6957:4;6954:1;6947:15;7312:127;7373:10;7368:3;7364:20;7361:1;7354:31;7404:4;7401:1;7394:15;7428:4;7425:1;7418:15;7444:135;7483:3;7504:17;;;7501:43;;7524:18;;:::i;:::-;-1:-1:-1;7571:1:10;7560:13;;7444:135::o;7584:184::-;7654:6;7707:2;7695:9;7686:7;7682:23;7678:32;7675:52;;;7723:1;7720;7713:12;7675:52;-1:-1:-1;7746:16:10;;7584:184;-1:-1:-1;7584:184:10:o;7773:380::-;7852:1;7848:12;;;;7895;;;7916:61;;7970:4;7962:6;7958:17;7948:27;;7916:61;8023:2;8015:6;8012:14;7992:18;7989:38;7986:161;;8069:10;8064:3;8060:20;8057:1;8050:31;8104:4;8101:1;8094:15;8132:4;8129:1;8122:15;8158:784;8260:6;8313:3;8301:9;8292:7;8288:23;8284:33;8281:53;;;8330:1;8327;8320:12;8281:53;8356:22;;:::i;:::-;8407:9;8401:16;8394:5;8387:31;8471:2;8460:9;8456:18;8450:25;8445:2;8438:5;8434:14;8427:49;8529:2;8518:9;8514:18;8508:25;8503:2;8496:5;8492:14;8485:49;8587:2;8576:9;8572:18;8566:25;8561:2;8554:5;8550:14;8543:49;8646:3;8635:9;8631:19;8625:26;8619:3;8612:5;8608:15;8601:51;8706:3;8695:9;8691:19;8685:26;8679:3;8672:5;8668:15;8661:51;8766:3;8755:9;8751:19;8745:26;8739:3;8732:5;8728:15;8721:51;8826:3;8815:9;8811:19;8805:26;8799:3;8792:5;8788:15;8781:51;8851:3;8907:2;8896:9;8892:18;8886:25;8881:2;8874:5;8870:14;8863:49;;8931:5;8921:15;;;8158:784;;;;:::o;9281:125::-;9321:4;9349:1;9346;9343:8;9340:34;;;9354:18;;:::i;:::-;-1:-1:-1;9391:9:10;;9281:125::o;10203:245::-;10270:6;10323:2;10311:9;10302:7;10298:23;10294:32;10291:52;;;10339:1;10336;10329:12;10291:52;10371:9;10365:16;10390:28;10412:5;10390:28;:::i;11316:545::-;11418:2;11413:3;11410:11;11407:448;;;11454:1;11479:5;11475:2;11468:17;11524:4;11520:2;11510:19;11594:2;11582:10;11578:19;11575:1;11571:27;11565:4;11561:38;11630:4;11618:10;11615:20;11612:47;;;-1:-1:-1;11653:4:10;11612:47;11708:2;11703:3;11699:12;11696:1;11692:20;11686:4;11682:31;11672:41;;11763:82;11781:2;11774:5;11771:13;11763:82;;;11826:17;;;11807:1;11796:13;11763:82;;12037:1206;12161:18;12156:3;12153:27;12150:53;;;12183:18;;:::i;:::-;12212:94;12302:3;12262:38;12294:4;12288:11;12262:38;:::i;:::-;12256:4;12212:94;:::i;:::-;12332:1;12357:2;12352:3;12349:11;12374:1;12369:616;;;;13029:1;13046:3;13043:93;;;-1:-1:-1;13102:19:10;;;13089:33;13043:93;-1:-1:-1;;11994:1:10;11990:11;;;11986:24;11982:29;11972:40;12018:1;12014:11;;;11969:57;13149:78;;12342:895;;12369:616;11263:1;11256:14;;;11300:4;11287:18;;-1:-1:-1;;12405:17:10;;;12506:9;12528:229;12542:7;12539:1;12536:14;12528:229;;;12631:19;;;12618:33;12603:49;;12738:4;12723:20;;;;12691:1;12679:14;;;;12558:12;12528:229;;;12532:3;12785;12776:7;12773:16;12770:159;;;12909:1;12905:6;12899:3;12893;12890:1;12886:11;12882:21;12878:34;12874:39;12861:9;12856:3;12852:19;12839:33;12835:79;12827:6;12820:95;12770:159;;;12972:1;12966:3;12963:1;12959:11;12955:19;12949:4;12942:33;12342:895;;12037:1206;;;:::o;13248:390::-;13407:2;13396:9;13389:21;13446:6;13441:2;13430:9;13426:18;13419:34;13503:6;13495;13490:2;13479:9;13475:18;13462:48;13559:1;13530:22;;;13554:2;13526:31;;;13519:42;;;;13622:2;13601:15;;;-1:-1:-1;;13597:29:10;13582:45;13578:54;;13248:390;-1:-1:-1;13248:390:10:o;13643:662::-;-1:-1:-1;;;;;13970:15:10;;;13952:34;;14022:15;;;14017:2;14002:18;;13995:43;14074:15;;;14069:2;14054:18;;14047:43;14126:15;;;14121:2;14106:18;;14099:43;14179:15;;14173:3;14158:19;;14151:44;14232:3;13932;14211:19;;14204:32;;;13895:4;;14253:46;;14279:19;;14271:6;14253:46;:::i;:::-;14245:54;13643:662;-1:-1:-1;;;;;;;;13643:662:10:o;14665:422::-;14754:1;14797:5;14754:1;14811:270;14832:7;14822:8;14819:21;14811:270;;;14891:4;14887:1;14883:6;14879:17;14873:4;14870:27;14867:53;;;14900:18;;:::i;:::-;14950:7;14940:8;14936:22;14933:55;;;14970:16;;;;14933:55;15049:22;;;;15009:15;;;;14811:270;;;14815:3;14665:422;;;;;:::o;15092:806::-;15141:5;15171:8;15161:80;;-1:-1:-1;15212:1:10;15226:5;;15161:80;15260:4;15250:76;;-1:-1:-1;15297:1:10;15311:5;;15250:76;15342:4;15360:1;15355:59;;;;15428:1;15423:130;;;;15335:218;;15355:59;15385:1;15376:10;;15399:5;;;15423:130;15460:3;15450:8;15447:17;15444:43;;;15467:18;;:::i;:::-;-1:-1:-1;;15523:1:10;15509:16;;15538:5;;15335:218;;15637:2;15627:8;15624:16;15618:3;15612:4;15609:13;15605:36;15599:2;15589:8;15586:16;15581:2;15575:4;15572:12;15568:35;15565:77;15562:159;;;-1:-1:-1;15674:19:10;;;15706:5;;15562:159;15753:34;15778:8;15772:4;15753:34;:::i;:::-;15823:6;15819:1;15815:6;15811:19;15802:7;15799:32;15796:58;;;15834:18;;:::i;:::-;15872:20;;15092:806;-1:-1:-1;;;15092:806:10:o;15903:131::-;15963:5;15992:36;16019:8;16013:4;15992:36;:::i;16039:168::-;16079:7;16145:1;16141;16137:6;16133:14;16130:1;16127:21;16122:1;16115:9;16108:17;16104:45;16101:71;;;16152:18;;:::i;:::-;-1:-1:-1;16192:9:10;;16039:168::o;16212:217::-;16252:1;16278;16268:132;;16322:10;16317:3;16313:20;16310:1;16303:31;16357:4;16354:1;16347:15;16385:4;16382:1;16375:15;16268:132;-1:-1:-1;16414:9:10;;16212:217::o;16434:268::-;16521:6;16574:2;16562:9;16553:7;16549:23;16545:32;16542:52;;;16590:1;16587;16580:12;16542:52;16622:9;16616:16;16641:31;16666:5;16641:31;:::i;17273:128::-;17313:3;17344:1;17340:6;17337:1;17334:13;17331:39;;;17350:18;;:::i;:::-;-1:-1:-1;17386:9:10;;17273:128::o;19101:1352::-;19227:3;19221:10;19254:18;19246:6;19243:30;19240:56;;;19276:18;;:::i;:::-;19305:97;19395:6;19355:38;19387:4;19381:11;19355:38;:::i;:::-;19349:4;19305:97;:::i;:::-;19457:4;;19521:2;19510:14;;19538:1;19533:663;;;;20240:1;20257:6;20254:89;;;-1:-1:-1;20309:19:10;;;20303:26;20254:89;-1:-1:-1;;11994:1:10;11990:11;;;11986:24;11982:29;11972:40;12018:1;12014:11;;;11969:57;20356:81;;19503:944;;19533:663;11263:1;11256:14;;;11300:4;11287:18;;-1:-1:-1;;19569:20:10;;;19687:236;19701:7;19698:1;19695:14;19687:236;;;19790:19;;;19784:26;19769:42;;19882:27;;;;19850:1;19838:14;;;;19717:19;;19687:236;;;19691:3;19951:6;19942:7;19939:19;19936:201;;;20012:19;;;20006:26;-1:-1:-1;;20095:1:10;20091:14;;;20107:3;20087:24;20083:37;20079:42;20064:58;20049:74;;19936:201;-1:-1:-1;;;;;20183:1:10;20167:14;;;20163:22;20150:36;;-1:-1:-1;19101:1352:10:o;21276:274::-;21405:3;21443:6;21437:13;21459:53;21505:6;21500:3;21493:4;21485:6;21481:17;21459:53;:::i;:::-;21528:16;;;;;21276:274;-1:-1:-1;;21276:274:10:o
Swarm Source
ipfs://36aa1d7c57341d491068eb52b81162d96db22a453d81893d0bf4e46d97791246
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.