false
true
0

Contract Address Details

0x1b836c9e935121dC2f6D0B296fCe353Ff01299ac

Contract Name
ConvexStrategyHUSDMainnet
Creator
0xf00dd2–bf5f7f at 0xc4804c–623480
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
26348048
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
This contract has been partially verified via Sourcify. View contract in Sourcify repository
Contract name:
ConvexStrategyHUSDMainnet




Optimization enabled
true
Compiler version
v0.5.16+commit.9c3226ce




Optimization runs
200
EVM Version
istanbul




Verified at
2026-04-22T08:17:12.418268Z

contracts/strategies/convex/ConvexStrategyHUSDMainnet.sol

pragma solidity 0.5.16;

import "./ConvexStrategy4Token.sol";

contract ConvexStrategyHUSDMainnet is ConvexStrategy4Token {

  address public husd_unused; // just a differentiator for the bytecode

  constructor() public {}

  function initializeStrategy(
    address _storage,
    address _vault
  ) public initializer {
    address underlying = address(0x5B5CFE992AdAC0C9D48E05854B2d91C73a003858);
    address rewardPool = address(0x353e489311b21355461353fEC2d02B73EF0eDe7f);
    address crv = address(0xD533a949740bb3306d119CC777fa900bA034cd52);
    address cvx = address(0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B);
    address dai = address(0x6B175474E89094C44Da98b954EedeAC495271d0F);
    address husdCurveDeposit = address(0x09672362833d8f703D5395ef3252D4Bfa51c15ca);
    ConvexStrategy4Token.initializeBaseStrategy(
      _storage,
      underlying,
      _vault,
      rewardPool, //rewardPool
      11,  // Pool id
      dai,
      1, //depositArrayPosition
      husdCurveDeposit
    );
    reward2WETH[crv] = [crv, weth];
    reward2WETH[cvx] = [cvx, weth];
    WETH2deposit = [weth, dai];
    rewardTokens = [crv, cvx];
    useUni[crv] = false;
    useUni[cvx] = false;
    useUni[dai] = false;
  }
}
        

/ERC20Detailed.sol

pragma solidity ^0.5.0;

import "./IERC20.sol";

/**
 * @dev Optional functions from the ERC20 standard.
 */
contract ERC20Detailed is IERC20 {
    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
     * these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory name, string memory symbol, uint8 decimals) public {
        _name = name;
        _symbol = symbol;
        _decimals = decimals;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view 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.
     *
     * 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 returns (uint8) {
        return _decimals;
    }
}
          

/IUniswapV2Pair.sol

// SPDX-License-Identifier: MIT
/**
 *Submitted for verification at Etherscan.io on 2020-05-05
*/

// File: contracts/interfaces/IUniswapV2Pair.sol

pragma solidity >=0.5.0;

interface IUniswapV2Pair {
    event Approval(address indexed owner, address indexed spender, uint value);
    event Transfer(address indexed from, address indexed to, uint value);

    function name() external pure returns (string memory);
    function symbol() external pure returns (string memory);
    function decimals() external pure returns (uint8);
    function totalSupply() external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint value) external returns (bool);
    function transfer(address to, uint value) external returns (bool);
    function transferFrom(address from, address to, uint value) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function PERMIT_TYPEHASH() external pure returns (bytes32);
    function nonces(address owner) external view returns (uint);

    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;

    event Mint(address indexed sender, uint amount0, uint amount1);
    event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint amount0In,
        uint amount1In,
        uint amount0Out,
        uint amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint);
    function factory() external view returns (address);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function price0CumulativeLast() external view returns (uint);
    function price1CumulativeLast() external view returns (uint);
    function kLast() external view returns (uint);

    function mint(address to) external returns (uint liquidity);
    function burn(address to) external returns (uint amount0, uint amount1);
    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
    function skim(address to) external;
    function sync() external;

    function initialize(address, address) external;
}
          

/

pragma solidity 0.5.16;

import "@openzeppelin/upgrades/contracts/Initializable.sol";
import "./Storage.sol";

// A clone of Governable supporting the Initializable interface and pattern
contract GovernableInit is Initializable {

  bytes32 internal constant _STORAGE_SLOT = 0xa7ec62784904ff31cbcc32d09932a58e7f1e4476e1d041995b37c917990b16dc;

  modifier onlyGovernance() {
    require(Storage(_storage()).isGovernance(msg.sender), "Not governance");
    _;
  }

  constructor() public {
    assert(_STORAGE_SLOT == bytes32(uint256(keccak256("eip1967.governableInit.storage")) - 1));
  }

  function initialize(address _store) public initializer {
    _setStorage(_store);
  }

  function _setStorage(address newStorage) private {
    bytes32 slot = _STORAGE_SLOT;
    // solhint-disable-next-line no-inline-assembly
    assembly {
      sstore(slot, newStorage)
    }
  }

  function setStorage(address _store) public onlyGovernance {
    require(_store != address(0), "new storage shouldn't be empty");
    _setStorage(_store);
  }

  function _storage() internal view returns (address str) {
    bytes32 slot = _STORAGE_SLOT;
    // solhint-disable-next-line no-inline-assembly
    assembly {
      str := sload(slot)
    }
  }

  function governance() public view returns (address) {
    return Storage(_storage()).governance();
  }
}
          

/

pragma solidity 0.5.16;

interface IController {

    event SharePriceChangeLog(
      address indexed vault,
      address indexed strategy,
      uint256 oldSharePrice,
      uint256 newSharePrice,
      uint256 timestamp
    );

    // [Grey list]
    // An EOA can safely interact with the system no matter what.
    // If you're using Metamask, you're using an EOA.
    // Only smart contracts may be affected by this grey list.
    //
    // This contract will not be able to ban any EOA from the system
    // even if an EOA is being added to the greyList, he/she will still be able
    // to interact with the whole system as if nothing happened.
    // Only smart contracts will be affected by being added to the greyList.
    // This grey list is only used in Vault.sol, see the code there for reference
    function greyList(address _target) external view returns(bool);

    function addVaultAndStrategy(address _vault, address _strategy) external;
    function doHardWork(address _vault) external;

    function salvage(address _token, uint256 amount) external;
    function salvageStrategy(address _strategy, address _token, uint256 amount) external;

    function notifyFee(address _underlying, uint256 fee) external;
    function profitSharingNumerator() external view returns (uint256);
    function profitSharingDenominator() external view returns (uint256);

    function feeRewardForwarder() external view returns(address);
    function setFeeRewardForwarder(address _value) external;

    function addHardWorker(address _worker) external;
}
          

/

pragma solidity 0.5.16;

import "@openzeppelin/upgrades/contracts/Initializable.sol";

contract BaseUpgradeableStrategyStorage {

  bytes32 internal constant _UNDERLYING_SLOT = 0xa1709211eeccf8f4ad5b6700d52a1a9525b5f5ae1e9e5f9e5a0c2fc23c86e530;
  bytes32 internal constant _VAULT_SLOT = 0xefd7c7d9ef1040fc87e7ad11fe15f86e1d11e1df03c6d7c87f7e1f4041f08d41;

  bytes32 internal constant _REWARD_TOKEN_SLOT = 0xdae0aafd977983cb1e78d8f638900ff361dc3c48c43118ca1dd77d1af3f47bbf;
  bytes32 internal constant _REWARD_POOL_SLOT = 0x3d9bb16e77837e25cada0cf894835418b38e8e18fbec6cfd192eb344bebfa6b8;
  bytes32 internal constant _SELL_FLOOR_SLOT = 0xc403216a7704d160f6a3b5c3b149a1226a6080f0a5dd27b27d9ba9c022fa0afc;
  bytes32 internal constant _SELL_SLOT = 0x656de32df98753b07482576beb0d00a6b949ebf84c066c765f54f26725221bb6;
  bytes32 internal constant _PAUSED_INVESTING_SLOT = 0xa07a20a2d463a602c2b891eb35f244624d9068572811f63d0e094072fb54591a;

  bytes32 internal constant _PROFIT_SHARING_NUMERATOR_SLOT = 0xe3ee74fb7893020b457d8071ed1ef76ace2bf4903abd7b24d3ce312e9c72c029;
  bytes32 internal constant _PROFIT_SHARING_DENOMINATOR_SLOT = 0x0286fd414602b432a8c80a0125e9a25de9bba96da9d5068c832ff73f09208a3b;

  bytes32 internal constant _NEXT_IMPLEMENTATION_SLOT = 0x29f7fcd4fe2517c1963807a1ec27b0e45e67c60a874d5eeac7a0b1ab1bb84447;
  bytes32 internal constant _NEXT_IMPLEMENTATION_TIMESTAMP_SLOT = 0x414c5263b05428f1be1bfa98e25407cc78dd031d0d3cd2a2e3d63b488804f22e;
  bytes32 internal constant _NEXT_IMPLEMENTATION_DELAY_SLOT = 0x82b330ca72bcd6db11a26f10ce47ebcfe574a9c646bccbc6f1cd4478eae16b31;

  bytes32 internal constant _REWARD_CLAIMABLE_SLOT = 0xbc7c0d42a71b75c3129b337a259c346200f901408f273707402da4b51db3b8e7;
  bytes32 internal constant _MULTISIG_SLOT = 0x3e9de78b54c338efbc04e3a091b87dc7efb5d7024738302c548fc59fba1c34e6;

  constructor() public {
    assert(_UNDERLYING_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.underlying")) - 1));
    assert(_VAULT_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.vault")) - 1));
    assert(_REWARD_TOKEN_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.rewardToken")) - 1));
    assert(_REWARD_POOL_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.rewardPool")) - 1));
    assert(_SELL_FLOOR_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.sellFloor")) - 1));
    assert(_SELL_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.sell")) - 1));
    assert(_PAUSED_INVESTING_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.pausedInvesting")) - 1));

    assert(_PROFIT_SHARING_NUMERATOR_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.profitSharingNumerator")) - 1));
    assert(_PROFIT_SHARING_DENOMINATOR_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.profitSharingDenominator")) - 1));

    assert(_NEXT_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.nextImplementation")) - 1));
    assert(_NEXT_IMPLEMENTATION_TIMESTAMP_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.nextImplementationTimestamp")) - 1));
    assert(_NEXT_IMPLEMENTATION_DELAY_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.nextImplementationDelay")) - 1));

    assert(_REWARD_CLAIMABLE_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.rewardClaimable")) - 1));
    assert(_MULTISIG_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.multiSig")) - 1));
  }

  function _setUnderlying(address _address) internal {
    setAddress(_UNDERLYING_SLOT, _address);
  }

  function underlying() public view returns (address) {
    return getAddress(_UNDERLYING_SLOT);
  }

  function _setRewardPool(address _address) internal {
    setAddress(_REWARD_POOL_SLOT, _address);
  }

  function rewardPool() public view returns (address) {
    return getAddress(_REWARD_POOL_SLOT);
  }

  function _setRewardToken(address _address) internal {
    setAddress(_REWARD_TOKEN_SLOT, _address);
  }

  function rewardToken() public view returns (address) {
    return getAddress(_REWARD_TOKEN_SLOT);
  }

  function _setVault(address _address) internal {
    setAddress(_VAULT_SLOT, _address);
  }

  function vault() public view returns (address) {
    return getAddress(_VAULT_SLOT);
  }

  // a flag for disabling selling for simplified emergency exit
  function _setSell(bool _value) internal {
    setBoolean(_SELL_SLOT, _value);
  }

  function sell() public view returns (bool) {
    return getBoolean(_SELL_SLOT);
  }

  function _setPausedInvesting(bool _value) internal {
    setBoolean(_PAUSED_INVESTING_SLOT, _value);
  }

  function pausedInvesting() public view returns (bool) {
    return getBoolean(_PAUSED_INVESTING_SLOT);
  }

  function _setSellFloor(uint256 _value) internal {
    setUint256(_SELL_FLOOR_SLOT, _value);
  }

  function sellFloor() public view returns (uint256) {
    return getUint256(_SELL_FLOOR_SLOT);
  }

  function _setProfitSharingNumerator(uint256 _value) internal {
    setUint256(_PROFIT_SHARING_NUMERATOR_SLOT, _value);
  }

  function profitSharingNumerator() public view returns (uint256) {
    return getUint256(_PROFIT_SHARING_NUMERATOR_SLOT);
  }

  function _setProfitSharingDenominator(uint256 _value) internal {
    setUint256(_PROFIT_SHARING_DENOMINATOR_SLOT, _value);
  }

  function profitSharingDenominator() public view returns (uint256) {
    return getUint256(_PROFIT_SHARING_DENOMINATOR_SLOT);
  }

  function allowedRewardClaimable() public view returns (bool) {
    return getBoolean(_REWARD_CLAIMABLE_SLOT);
  }

  function _setRewardClaimable(bool _value) internal {
    setBoolean(_REWARD_CLAIMABLE_SLOT, _value);
  }

  function multiSig() public view returns(address) {
    return getAddress(_MULTISIG_SLOT);
  }

  function _setMultiSig(address _address) internal {
    setAddress(_MULTISIG_SLOT, _address);
  }

  // upgradeability

  function _setNextImplementation(address _address) internal {
    setAddress(_NEXT_IMPLEMENTATION_SLOT, _address);
  }

  function nextImplementation() public view returns (address) {
    return getAddress(_NEXT_IMPLEMENTATION_SLOT);
  }

  function _setNextImplementationTimestamp(uint256 _value) internal {
    setUint256(_NEXT_IMPLEMENTATION_TIMESTAMP_SLOT, _value);
  }

  function nextImplementationTimestamp() public view returns (uint256) {
    return getUint256(_NEXT_IMPLEMENTATION_TIMESTAMP_SLOT);
  }

  function _setNextImplementationDelay(uint256 _value) internal {
    setUint256(_NEXT_IMPLEMENTATION_DELAY_SLOT, _value);
  }

  function nextImplementationDelay() public view returns (uint256) {
    return getUint256(_NEXT_IMPLEMENTATION_DELAY_SLOT);
  }

  function setBoolean(bytes32 slot, bool _value) internal {
    setUint256(slot, _value ? 1 : 0);
  }

  function getBoolean(bytes32 slot) internal view returns (bool) {
    return (getUint256(slot) == 1);
  }

  function setAddress(bytes32 slot, address _address) internal {
    // solhint-disable-next-line no-inline-assembly
    assembly {
      sstore(slot, _address)
    }
  }

  function setUint256(bytes32 slot, uint256 _value) internal {
    // solhint-disable-next-line no-inline-assembly
    assembly {
      sstore(slot, _value)
    }
  }

  function getAddress(bytes32 slot) internal view returns (address str) {
    // solhint-disable-next-line no-inline-assembly
    assembly {
      str := sload(slot)
    }
  }

  function getUint256(bytes32 slot) internal view returns (uint256 str) {
    // solhint-disable-next-line no-inline-assembly
    assembly {
      str := sload(slot)
    }
  }
}
          

/ICurveDeposit_4token.sol

pragma solidity 0.5.16;

interface ICurveDeposit_4token {
  function get_virtual_price() external view returns (uint);
  function add_liquidity(
    uint256[4] calldata amounts,
    uint256 min_mint_amount
  ) external;
  function remove_liquidity_imbalance(
    uint256[4] calldata amounts,
    uint256 max_burn_amount
  ) external;
  function remove_liquidity(
    uint256 _amount,
    uint256[4] calldata amounts
  ) external;
  function exchange(
    int128 from, int128 to, uint256 _from_amount, uint256 _min_to_amount
  ) external;
  function calc_token_amount(
    uint256[4] calldata amounts,
    bool deposit
  ) external view returns(uint);
}
          

/IBaseRewardPool.sol

pragma solidity 0.5.16;

interface IBaseRewardPool {
    function balanceOf(address account) external view returns(uint256 amount);
    function pid() external view returns (uint256 _pid);
    function stakingToken() external view returns (address _stakingToken);
    function getReward() external;
    function stake(uint256 _amount) external;
    function stakeAll() external;
    function withdraw(uint256 amount, bool claim) external;
    function withdrawAll(bool claim) external;
    function withdrawAndUnwrap(uint256 amount, bool claim) external;
    function withdrawAllAndUnwrap(bool claim) external;
}
          

/SafeERC20.sol

pragma solidity ^0.5.0;

import "./IERC20.sol";
import "../../math/SafeMath.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 ERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves.

        // A Solidity high level call has three parts:
        //  1. The target address is checked to verify it contains contract code
        //  2. The call itself is made, and success asserted
        //  3. The return value is decoded, which in turn checks the size of the returned data.
        // solhint-disable-next-line max-line-length
        require(address(token).isContract(), "SafeERC20: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = address(token).call(data);
        require(success, "SafeERC20: low-level call failed");

        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}
          

/

pragma solidity ^0.5.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     *
     * _Available since v2.4.0._
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}
          

/

pragma solidity ^0.5.5;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following 
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @dev Converts an `address` into `address payable`. Note that this is
     * simply a type cast: the actual underlying value is not changed.
     *
     * _Available since v2.4.0._
     */
    function toPayable(address account) internal pure returns (address payable) {
        return address(uint160(account));
    }

    /**
     * @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].
     *
     * _Available since v2.4.0._
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-call-value
        (bool success, ) = recipient.call.value(amount)("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }
}
          

/

pragma solidity 0.5.16;

import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "../../base/interface/uniswap/IUniswapV2Router02.sol";
import "../../base/interface/IStrategy.sol";
import "../../base/interface/IVault.sol";
import "../../base/upgradability/BaseUpgradeableStrategy.sol";
import "../../base/interface/uniswap/IUniswapV2Pair.sol";
import "./interface/IBooster.sol";
import "./interface/IBaseRewardPool.sol";
import "../../base/interface/curve/ICurveDeposit_4token.sol";


contract ConvexStrategy4Token is IStrategy, BaseUpgradeableStrategy {

  using SafeMath for uint256;
  using SafeERC20 for IERC20;

  address public constant uniswapRouterV2 = address(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
  address public constant sushiswapRouterV2 = address(0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F);
  address public constant booster = address(0xF403C135812408BFbE8713b5A23a04b3D48AAE31);
  address public constant weth = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
  address public constant multiSigAddr = 0xF49440C1F012d041802b25A73e5B0B9166a75c02;
  uint256 public constant hodlRatioBase = 10000;

  // additional storage slots (on top of BaseUpgradeableStrategy ones) are defined here
  bytes32 internal constant _POOLID_SLOT = 0x3fd729bfa2e28b7806b03a6e014729f59477b530f995be4d51defc9dad94810b;
  bytes32 internal constant _DEPOSIT_TOKEN_SLOT = 0x219270253dbc530471c88a9e7c321b36afda219583431e7b6c386d2d46e70c86;
  bytes32 internal constant _DEPOSIT_RECEIPT_SLOT = 0x414478d5ad7f54ead8a3dd018bba4f8d686ba5ab5975cd376e0c98f98fb713c5;
  bytes32 internal constant _DEPOSIT_ARRAY_POSITION_SLOT = 0xb7c50ef998211fff3420379d0bf5b8dfb0cee909d1b7d9e517f311c104675b09;
  bytes32 internal constant _CURVE_DEPOSIT_SLOT = 0xb306bb7adebd5a22f5e4cdf1efa00bc5f62d4f5554ef9d62c1b16327cd3ab5f9;
  bytes32 internal constant _HODL_RATIO_SLOT = 0xb487e573671f10704ed229d25cf38dda6d287a35872859d096c0395110a0adb1;
  bytes32 internal constant _HODL_VAULT_SLOT = 0xc26d330f887c749cb38ae7c37873ff08ac4bba7aec9113c82d48a0cf6cc145f2;

  address[] public WETH2deposit;
  mapping (address => address[]) public reward2WETH;
  mapping (address => bool) public useUni;
  address[] public rewardTokens;

  constructor() public BaseUpgradeableStrategy() {
    assert(_POOLID_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.poolId")) - 1));
    assert(_DEPOSIT_TOKEN_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.depositToken")) - 1));
    assert(_DEPOSIT_RECEIPT_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.depositReceipt")) - 1));
    assert(_DEPOSIT_ARRAY_POSITION_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.depositArrayPosition")) - 1));
    assert(_CURVE_DEPOSIT_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.curveDeposit")) - 1));
    assert(_HODL_RATIO_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.hodlRatio")) - 1));
    assert(_HODL_VAULT_SLOT == bytes32(uint256(keccak256("eip1967.strategyStorage.hodlVault")) - 1));
  }

  function initializeBaseStrategy(
    address _storage,
    address _underlying,
    address _vault,
    address _rewardPool,
    uint256 _poolID,
    address _depositToken,
    uint256 _depositArrayPosition,
    address _curveDeposit
  ) public initializer {

    BaseUpgradeableStrategy.initialize(
      _storage,
      _underlying,
      _vault,
      _rewardPool,
      weth,
      300, // profit sharing numerator
      1000, // profit sharing denominator
      true, // sell
      1e18, // sell floor
      12 hours // implementation change delay
    );

    address _lpt;
    address _depositReceipt;
    (_lpt,_depositReceipt,,,,) = IBooster(booster).poolInfo(_poolID);
    require(_lpt == underlying(), "Pool Info does not match underlying");
    require(_depositArrayPosition < 4, "Deposit array position out of bounds");
    _setDepositArrayPosition(_depositArrayPosition);
    _setPoolId(_poolID);
    _setDepositToken(_depositToken);
    _setDepositReceipt(_depositReceipt);
    _setCurveDeposit(_curveDeposit);
    setHodlRatio(1000);
    setHodlVault(multiSigAddr);
    WETH2deposit = new address[](0);
    rewardTokens = new address[](0);
  }

  function setHodlRatio(uint256 _value) public onlyGovernance {
    setUint256(_HODL_RATIO_SLOT, _value);
  }

  function hodlRatio() public view returns (uint256) {
    return getUint256(_HODL_RATIO_SLOT);
  }

  function setHodlVault(address _address) public onlyGovernance {
    setAddress(_HODL_VAULT_SLOT, _address);
  }

  function hodlVault() public view returns (address) {
    return getAddress(_HODL_VAULT_SLOT);
  }

  function depositArbCheck() public view returns(bool) {
    return true;
  }

  function rewardPoolBalance() internal view returns (uint256 bal) {
      bal = IBaseRewardPool(rewardPool()).balanceOf(address(this));
  }

  function exitRewardPool() internal {
      uint256 stakedBalance = rewardPoolBalance();
      if (stakedBalance != 0) {
          IBaseRewardPool(rewardPool()).withdrawAll(true);
      }
      uint256 depositBalance = IERC20(depositReceipt()).balanceOf(address(this));
      if (depositBalance != 0) {
        IBooster(booster).withdrawAll(poolId());
      }
  }

  function partialWithdrawalRewardPool(uint256 amount) internal {
    IBaseRewardPool(rewardPool()).withdraw(amount, false);  //don't claim rewards at this point
    uint256 depositBalance = IERC20(depositReceipt()).balanceOf(address(this));
    if (depositBalance != 0) {
      IBooster(booster).withdrawAll(poolId());
    }
  }

  function emergencyExitRewardPool() internal {
    uint256 stakedBalance = rewardPoolBalance();
    if (stakedBalance != 0) {
        IBaseRewardPool(rewardPool()).withdrawAll(false); //don't claim rewards
    }
    uint256 depositBalance = IERC20(depositReceipt()).balanceOf(address(this));
    if (depositBalance != 0) {
      IBooster(booster).withdrawAll(poolId());
    }
  }

  function unsalvagableTokens(address token) public view returns (bool) {
    return (token == rewardToken() || token == underlying() || token == depositReceipt());
  }

  function enterRewardPool() internal {
    uint256 entireBalance = IERC20(underlying()).balanceOf(address(this));
    IERC20(underlying()).safeApprove(booster, 0);
    IERC20(underlying()).safeApprove(booster, entireBalance);
    IBooster(booster).depositAll(poolId(), true); //deposit and stake
  }

  /*
  *   In case there are some issues discovered about the pool or underlying asset
  *   Governance can exit the pool properly
  *   The function is only used for emergency to exit the pool
  */
  function emergencyExit() public onlyGovernance {
    emergencyExitRewardPool();
    _setPausedInvesting(true);
  }

  /*
  *   Resumes the ability to invest into the underlying reward pools
  */

  function continueInvesting() public onlyGovernance {
    _setPausedInvesting(false);
  }

  function setDepositLiquidationPath(address [] memory _route) public onlyGovernance {
    require(_route[0] == weth, "Path should start with WETH");
    require(_route[_route.length-1] == depositToken(), "Path should end with depositToken");
    WETH2deposit = _route;
  }

  function setRewardLiquidationPath(address [] memory _route) public onlyGovernance {
    require(_route[_route.length-1] == weth, "Path should end with WETH");
    bool isReward = false;
    for(uint256 i = 0; i < rewardTokens.length; i++){
      if (_route[0] == rewardTokens[i]) {
        isReward = true;
      }
    }
    require(isReward, "Path should start with a rewardToken");
    reward2WETH[_route[0]] = _route;
  }

  function addRewardToken(address _token, address[] memory _path2WETH) public onlyGovernance {
    require(_path2WETH[_path2WETH.length-1] == weth, "Path should end with WETH");
    require(_path2WETH[0] == _token, "Path should start with rewardToken");
    rewardTokens.push(_token);
    reward2WETH[_token] = _path2WETH;
  }

  // We assume that all the tradings can be done on Sushiswap
  function _liquidateReward() internal {
    if (!sell()) {
      // Profits can be disabled for possible simplified and rapoolId exit
      emit ProfitsNotCollected(sell(), false);
      return;
    }

    for(uint256 i = 0; i < rewardTokens.length; i++){
      address token = rewardTokens[i];
      uint256 rewardBalance = IERC20(token).balanceOf(address(this));
      if (rewardBalance == 0 || reward2WETH[token].length < 2) {
        continue;
      }

      uint256 toHodl = rewardBalance.mul(hodlRatio()).div(hodlRatioBase);
      if (toHodl > 0) {
        IERC20(token).safeTransfer(hodlVault(), toHodl);
        rewardBalance = rewardBalance.sub(toHodl);
        if (rewardBalance == 0) {
          continue;
        }
      }

      address routerV2;
      if(useUni[token]) {
        routerV2 = uniswapRouterV2;
      } else {
        routerV2 = sushiswapRouterV2;
      }
      IERC20(token).safeApprove(routerV2, 0);
      IERC20(token).safeApprove(routerV2, rewardBalance);
      // we can accept 1 as the minimum because this will be called only by a trusted worker
      IUniswapV2Router02(routerV2).swapExactTokensForTokens(
        rewardBalance, 1, reward2WETH[token], address(this), block.timestamp
      );
    }

    uint256 rewardBalance = IERC20(weth).balanceOf(address(this));

    notifyProfitInRewardToken(rewardBalance);
    uint256 remainingRewardBalance = IERC20(rewardToken()).balanceOf(address(this));

    if (remainingRewardBalance == 0) {
      return;
    }

    address routerV2;
    if(useUni[depositToken()]) {
      routerV2 = uniswapRouterV2;
    } else {
      routerV2 = sushiswapRouterV2;
    }
    // allow Uniswap to sell our reward
    IERC20(rewardToken()).safeApprove(routerV2, 0);
    IERC20(rewardToken()).safeApprove(routerV2, remainingRewardBalance);

    // we can accept 1 as minimum because this is called only by a trusted role
    uint256 amountOutMin = 1;

    IUniswapV2Router02(routerV2).swapExactTokensForTokens(
      remainingRewardBalance,
      amountOutMin,
      WETH2deposit,
      address(this),
      block.timestamp
    );

    uint256 tokenBalance = IERC20(depositToken()).balanceOf(address(this));
    if (tokenBalance > 0) {
      depositCurve();
    }
  }

  function depositCurve() internal {
    uint256 tokenBalance = IERC20(depositToken()).balanceOf(address(this));
    IERC20(depositToken()).safeApprove(curveDeposit(), 0);
    IERC20(depositToken()).safeApprove(curveDeposit(), tokenBalance);

    uint256[4] memory depositArray;
    depositArray[depositArrayPosition()] = tokenBalance;

    // we can accept 0 as minimum, this will be called only by trusted roles
    uint256 minimum = 0;
    ICurveDeposit_4token(curveDeposit()).add_liquidity(depositArray, minimum);
  }


  /*
  *   Stakes everything the strategy holds into the reward pool
  */
  function investAllUnderlying() internal onlyNotPausedInvesting {
    // this check is needed, because most of the SNX reward pools will revert if
    // you try to stake(0).
    if(IERC20(underlying()).balanceOf(address(this)) > 0) {
      enterRewardPool();
    }
  }

  /*
  *   Withdraws all the asset to the vault
  */
  function withdrawAllToVault() public restricted {
    if (address(rewardPool()) != address(0)) {
      exitRewardPool();
    }
    _liquidateReward();
    IERC20(underlying()).safeTransfer(vault(), IERC20(underlying()).balanceOf(address(this)));
  }

  /*
  *   Withdraws all the asset to the vault
  */
  function withdrawToVault(uint256 amount) public restricted {
    // Typically there wouldn't be any amount here
    // however, it is possible because of the emergencyExit
    uint256 entireBalance = IERC20(underlying()).balanceOf(address(this));

    if(amount > entireBalance){
      // While we have the check above, we still using SafeMath below
      // for the peace of mind (in case something gets changed in between)
      uint256 needToWithdraw = amount.sub(entireBalance);
      uint256 toWithdraw = Math.min(rewardPoolBalance(), needToWithdraw);
      partialWithdrawalRewardPool(toWithdraw);
    }
    IERC20(underlying()).safeTransfer(vault(), amount);
  }

  /*
  *   Note that we currently do not have a mechanism here to include the
  *   amount of reward that is accrued.
  */
  function investedUnderlyingBalance() external view returns (uint256) {
    return rewardPoolBalance()
      .add(IERC20(depositReceipt()).balanceOf(address(this)))
      .add(IERC20(underlying()).balanceOf(address(this)));
  }

  /*
  *   Governance or Controller can claim coins that are somehow transferred into the contract
  *   Note that they cannot come in take away coins that are used and defined in the strategy itself
  */
  function salvage(address recipient, address token, uint256 amount) external onlyControllerOrGovernance {
     // To make sure that governance cannot come in and take away the coins
    require(!unsalvagableTokens(token), "token is defined as not salvagable");
    IERC20(token).safeTransfer(recipient, amount);
  }

  /*
  *   Get the reward, sell it in exchange for underlying, invest what you got.
  *   It's not much, but it's honest work.
  *
  *   Note that although `onlyNotPausedInvesting` is not added here,
  *   calling `investAllUnderlying()` affectively blocks the usage of `doHardWork`
  *   when the investing is being paused by governance.
  */
  function doHardWork() external onlyNotPausedInvesting restricted {
    IBaseRewardPool(rewardPool()).getReward();
    _liquidateReward();
    investAllUnderlying();
  }

  /**
  * Can completely disable claiming UNI rewards and selling. Good for emergency withdraw in the
  * simplest possible way.
  */
  function setSell(bool s) public onlyGovernance {
    _setSell(s);
  }

  /**
  * Sets the minimum amount of CRV needed to trigger a sale.
  */
  function setSellFloor(uint256 floor) public onlyGovernance {
    _setSellFloor(floor);
  }

  // masterchef rewards pool ID
  function _setPoolId(uint256 _value) internal {
    setUint256(_POOLID_SLOT, _value);
  }

  function poolId() public view returns (uint256) {
    return getUint256(_POOLID_SLOT);
  }

  function _setDepositToken(address _address) internal {
    setAddress(_DEPOSIT_TOKEN_SLOT, _address);
  }

  function depositToken() public view returns (address) {
    return getAddress(_DEPOSIT_TOKEN_SLOT);
  }

  function _setDepositReceipt(address _address) internal {
    setAddress(_DEPOSIT_RECEIPT_SLOT, _address);
  }

  function depositReceipt() public view returns (address) {
    return getAddress(_DEPOSIT_RECEIPT_SLOT);
  }

  function _setDepositArrayPosition(uint256 _value) internal {
    setUint256(_DEPOSIT_ARRAY_POSITION_SLOT, _value);
  }

  function depositArrayPosition() public view returns (uint256) {
    return getUint256(_DEPOSIT_ARRAY_POSITION_SLOT);
  }

  function _setCurveDeposit(address _address) internal {
    setAddress(_CURVE_DEPOSIT_SLOT, _address);
  }

  function curveDeposit() public view returns (address) {
    return getAddress(_CURVE_DEPOSIT_SLOT);
  }

  function finalizeUpgrade() external onlyGovernance {
    _finalizeUpgrade();
    setHodlVault(multiSigAddr);
    setHodlRatio(1000); // 10%
  }
}
          

/

pragma solidity 0.5.16;

contract Storage {

  address public governance;
  address public controller;

  constructor() public {
    governance = msg.sender;
  }

  modifier onlyGovernance() {
    require(isGovernance(msg.sender), "Not governance");
    _;
  }

  function setGovernance(address _governance) public onlyGovernance {
    require(_governance != address(0), "new governance shouldn't be empty");
    governance = _governance;
  }

  function setController(address _controller) public onlyGovernance {
    require(_controller != address(0), "new controller shouldn't be empty");
    controller = _controller;
  }

  function isGovernance(address account) public view returns (bool) {
    return account == governance;
  }

  function isController(address account) public view returns (bool) {
    return account == controller;
  }
}
          

/

pragma solidity 0.5.16;

interface IFeeRewardForwarderV6 {
    function poolNotifyFixedTarget(address _token, uint256 _amount) external;

    function notifyFeeAndBuybackAmounts(uint256 _feeAmount, address _pool, uint256 _buybackAmount) external;
    function notifyFeeAndBuybackAmounts(address _token, uint256 _feeAmount, address _pool, uint256 _buybackAmount) external;
    function profitSharingPool() external view returns (address);
    function configureLiquidation(address[] calldata _path, bytes32[] calldata _dexes) external;
}
          

/

pragma solidity 0.5.16;

import "./GovernableInit.sol";

// A clone of Governable supporting the Initializable interface and pattern
contract ControllableInit is GovernableInit {

  constructor() public {
  }

  function initialize(address _storage) public initializer {
    GovernableInit.initialize(_storage);
  }

  modifier onlyController() {
    require(Storage(_storage()).isController(msg.sender), "Not a controller");
    _;
  }

  modifier onlyControllerOrGovernance(){
    require((Storage(_storage()).isController(msg.sender) || Storage(_storage()).isGovernance(msg.sender)),
      "The caller must be controller or governance");
    _;
  }

  function controller() public view returns (address) {
    return Storage(_storage()).controller();
  }
}
          

/IUniswapV2Router02.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;

import './IUniswapV2Router01.sol';

interface IUniswapV2Router02 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);
    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);

    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}
          

/

pragma solidity ^0.5.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow, so we distribute
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }
}
          

/IERC20.sol

pragma solidity ^0.5.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see {ERC20Detailed}.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}
          

/

pragma solidity >=0.4.24 <0.7.0;


/**
 * @title Initializable
 *
 * @dev Helper contract to support initializer functions. To use it, replace
 * the constructor with a function that has the `initializer` modifier.
 * WARNING: Unlike constructors, initializer functions must be manually
 * invoked. This applies both to deploying an Initializable contract, as well
 * as extending an Initializable contract via inheritance.
 * WARNING: When used with inheritance, manual care must be taken to not invoke
 * a parent initializer twice, or ensure that all initializers are idempotent,
 * because this is not dealt with automatically as with constructors.
 */
contract Initializable {

  /**
   * @dev Indicates that the contract has been initialized.
   */
  bool private initialized;

  /**
   * @dev Indicates that the contract is in the process of being initialized.
   */
  bool private initializing;

  /**
   * @dev Modifier to use in the initializer function of a contract.
   */
  modifier initializer() {
    require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized");

    bool isTopLevelCall = !initializing;
    if (isTopLevelCall) {
      initializing = true;
      initialized = true;
    }

    _;

    if (isTopLevelCall) {
      initializing = false;
    }
  }

  /// @dev Returns true if and only if the function is running in the constructor
  function isConstructor() private view returns (bool) {
    // extcodesize checks the size of the code stored in an address, and
    // address returns the current address. Since the code is still not
    // deployed when running a constructor, any checks on its code size will
    // yield zero, making it an effective way to detect if a contract is
    // under construction or not.
    address self = address(this);
    uint256 cs;
    assembly { cs := extcodesize(self) }
    return cs == 0;
  }

  // Reserved storage space to allow for layout changes in the future.
  uint256[50] private ______gap;
}
          

/IUniswapV2Router01.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);
    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
          

/IBooster.sol

pragma solidity 0.5.16;

interface IBooster {
    function deposit(uint256 _pid, uint256 _amount, bool _stake) external;
    function depositAll(uint256 _pid, bool _stake) external;
    function withdraw(uint256 _pid, uint256 _amount) external;
    function withdrawAll(uint256 _pid) external;
    function poolInfo(uint256 _pid) external view returns (address lpToken, address, address, address, address, bool);
    function earmarkRewards(uint256 _pid) external;
}
          

/

pragma solidity 0.5.16;

import "@openzeppelin/upgrades/contracts/Initializable.sol";
import "./BaseUpgradeableStrategyStorage.sol";
import "../inheritance/ControllableInit.sol";
import "../interface/IController.sol";
import "../interface/IFeeRewardForwarderV6.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";

contract BaseUpgradeableStrategy is Initializable, ControllableInit, BaseUpgradeableStrategyStorage {
  using SafeMath for uint256;
  using SafeERC20 for IERC20;

  event ProfitsNotCollected(bool sell, bool floor);
  event ProfitLogInReward(uint256 profitAmount, uint256 feeAmount, uint256 timestamp);
  event ProfitAndBuybackLog(uint256 profitAmount, uint256 feeAmount, uint256 timestamp);

  modifier restricted() {
    require(msg.sender == vault() || msg.sender == controller()
      || msg.sender == governance(),
      "The sender has to be the controller, governance, or vault");
    _;
  }

  // This is only used in `investAllUnderlying()`
  // The user can still freely withdraw from the strategy
  modifier onlyNotPausedInvesting() {
    require(!pausedInvesting(), "Action blocked as the strategy is in emergency state");
    _;
  }

  constructor() public BaseUpgradeableStrategyStorage() {
  }

  function initialize(
    address _storage,
    address _underlying,
    address _vault,
    address _rewardPool,
    address _rewardToken,
    uint256 _profitSharingNumerator,
    uint256 _profitSharingDenominator,
    bool _sell,
    uint256 _sellFloor,
    uint256 _implementationChangeDelay
  ) public initializer {
    ControllableInit.initialize(
      _storage
    );
    _setUnderlying(_underlying);
    _setVault(_vault);
    _setRewardPool(_rewardPool);
    _setRewardToken(_rewardToken);
    _setProfitSharingNumerator(_profitSharingNumerator);
    _setProfitSharingDenominator(_profitSharingDenominator);

    _setSell(_sell);
    _setSellFloor(_sellFloor);
    _setNextImplementationDelay(_implementationChangeDelay);
    _setPausedInvesting(false);
  }

  /**
  * Schedules an upgrade for this vault's proxy.
  */
  function scheduleUpgrade(address impl) public onlyGovernance {
    _setNextImplementation(impl);
    _setNextImplementationTimestamp(block.timestamp.add(nextImplementationDelay()));
  }

  function _finalizeUpgrade() internal {
    _setNextImplementation(address(0));
    _setNextImplementationTimestamp(0);
  }

  function shouldUpgrade() external view returns (bool, address) {
    return (
      nextImplementationTimestamp() != 0
        && block.timestamp > nextImplementationTimestamp()
        && nextImplementation() != address(0),
      nextImplementation()
    );
  }

  // reward notification

  function notifyProfitInRewardToken(uint256 _rewardBalance) internal {
    if( _rewardBalance > 0 ){
      uint256 feeAmount = _rewardBalance.mul(profitSharingNumerator()).div(profitSharingDenominator());
      emit ProfitLogInReward(_rewardBalance, feeAmount, block.timestamp);
      IERC20(rewardToken()).safeApprove(controller(), 0);
      IERC20(rewardToken()).safeApprove(controller(), feeAmount);

      IController(controller()).notifyFee(
        rewardToken(),
        feeAmount
      );
    } else {
      emit ProfitLogInReward(0, 0, block.timestamp);
    }
  }

  function notifyProfitAndBuybackInRewardToken(uint256 _rewardBalance, address pool, uint256 _buybackRatio) internal {
    if( _rewardBalance > 0 ){
      uint256 feeAmount = _rewardBalance.mul(profitSharingNumerator()).div(profitSharingDenominator());
      uint256 buybackAmount = _rewardBalance.sub(feeAmount).mul(_buybackRatio).div(10000);

      address forwarder = IController(controller()).feeRewardForwarder();
      emit ProfitAndBuybackLog(_rewardBalance, feeAmount, block.timestamp);

      IERC20(rewardToken()).safeApprove(forwarder, 0);
      IERC20(rewardToken()).safeApprove(forwarder, _rewardBalance);

      IFeeRewardForwarderV6(forwarder).notifyFeeAndBuybackAmounts(
        rewardToken(),
        feeAmount,
        pool,
        buybackAmount
      );
    } else {
      emit ProfitAndBuybackLog(0, 0, block.timestamp);
    }
  }
}
          

/

pragma solidity 0.5.16;

interface IVault {

    function initializeVault(
      address _storage,
      address _underlying,
      uint256 _toInvestNumerator,
      uint256 _toInvestDenominator
    ) external ;

    function balanceOf(address) external view returns (uint256);

    function underlyingBalanceInVault() external view returns (uint256);
    function underlyingBalanceWithInvestment() external view returns (uint256);

    // function store() external view returns (address);
    function governance() external view returns (address);
    function controller() external view returns (address);
    function underlying() external view returns (address);
    function strategy() external view returns (address);

    function setStrategy(address _strategy) external;
    function announceStrategyUpdate(address _strategy) external;
    function setVaultFractionToInvest(uint256 numerator, uint256 denominator) external;

    function deposit(uint256 amountWei) external;
    function depositFor(uint256 amountWei, address holder) external;

    function withdrawAll() external;
    function withdraw(uint256 numberOfShares) external;
    function getPricePerFullShare() external view returns (uint256);

    function underlyingBalanceWithInvestmentForHolder(address holder) view external returns (uint256);

    // hard work should be callable only by the controller (by the hard worker) or by governance
    function doHardWork() external;
}
          

/

pragma solidity 0.5.16;

interface IStrategy {
    
    function unsalvagableTokens(address tokens) external view returns (bool);
    
    function governance() external view returns (address);
    function controller() external view returns (address);
    function underlying() external view returns (address);
    function vault() external view returns (address);

    function withdrawAllToVault() external;
    function withdrawToVault(uint256 amount) external;

    function investedUnderlyingBalance() external view returns (uint256); // itsNotMuch()

    // should only be called by controller
    function salvage(address recipient, address token, uint256 amount) external;

    function doHardWork() external;
    function depositArbCheck() external view returns(bool);
}
          

Compiler Settings

{"remappings":[],"optimizer":{"runs":200,"enabled":true},"metadata":{"useLiteralContent":true},"libraries":{},"evmVersion":"istanbul","compilationTarget":{"contracts/strategies/convex/ConvexStrategyHUSDMainnet.sol":"ConvexStrategyHUSDMainnet"}}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","payable":false,"inputs":[]},{"type":"event","name":"ProfitAndBuybackLog","inputs":[{"type":"uint256","name":"profitAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"feeAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ProfitLogInReward","inputs":[{"type":"uint256","name":"profitAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"feeAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ProfitsNotCollected","inputs":[{"type":"bool","name":"sell","internalType":"bool","indexed":false},{"type":"bool","name":"floor","internalType":"bool","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"WETH2deposit","inputs":[{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addRewardToken","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"address[]","name":"_path2WETH","internalType":"address[]"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"allowedRewardClaimable","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"booster","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"continueInvesting","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"controller","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"curveDeposit","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"depositArbCheck","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"depositArrayPosition","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"depositReceipt","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"depositToken","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"doHardWork","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"emergencyExit","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"finalizeUpgrade","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"governance","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"hodlRatio","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"hodlRatioBase","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"hodlVault","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"husd_unused","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_storage","internalType":"address"},{"type":"address","name":"_underlying","internalType":"address"},{"type":"address","name":"_vault","internalType":"address"},{"type":"address","name":"_rewardPool","internalType":"address"},{"type":"address","name":"_rewardToken","internalType":"address"},{"type":"uint256","name":"_profitSharingNumerator","internalType":"uint256"},{"type":"uint256","name":"_profitSharingDenominator","internalType":"uint256"},{"type":"bool","name":"_sell","internalType":"bool"},{"type":"uint256","name":"_sellFloor","internalType":"uint256"},{"type":"uint256","name":"_implementationChangeDelay","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_storage","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initializeBaseStrategy","inputs":[{"type":"address","name":"_storage","internalType":"address"},{"type":"address","name":"_underlying","internalType":"address"},{"type":"address","name":"_vault","internalType":"address"},{"type":"address","name":"_rewardPool","internalType":"address"},{"type":"uint256","name":"_poolID","internalType":"uint256"},{"type":"address","name":"_depositToken","internalType":"address"},{"type":"uint256","name":"_depositArrayPosition","internalType":"uint256"},{"type":"address","name":"_curveDeposit","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initializeStrategy","inputs":[{"type":"address","name":"_storage","internalType":"address"},{"type":"address","name":"_vault","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"investedUnderlyingBalance","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"multiSig","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"multiSigAddr","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"nextImplementation","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nextImplementationDelay","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nextImplementationTimestamp","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"pausedInvesting","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"poolId","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"profitSharingDenominator","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"profitSharingNumerator","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"reward2WETH","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"rewardPool","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"rewardToken","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"rewardTokens","inputs":[{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"salvage","inputs":[{"type":"address","name":"recipient","internalType":"address"},{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"scheduleUpgrade","inputs":[{"type":"address","name":"impl","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"sell","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"sellFloor","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setDepositLiquidationPath","inputs":[{"type":"address[]","name":"_route","internalType":"address[]"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setHodlRatio","inputs":[{"type":"uint256","name":"_value","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setHodlVault","inputs":[{"type":"address","name":"_address","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setRewardLiquidationPath","inputs":[{"type":"address[]","name":"_route","internalType":"address[]"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setSell","inputs":[{"type":"bool","name":"s","internalType":"bool"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setSellFloor","inputs":[{"type":"uint256","name":"floor","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setStorage","inputs":[{"type":"address","name":"_store","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"},{"type":"address","name":"","internalType":"address"}],"name":"shouldUpgrade","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"sushiswapRouterV2","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"underlying","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"uniswapRouterV2","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"unsalvagableTokens","inputs":[{"type":"address","name":"token","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"useUni","inputs":[{"type":"address","name":"","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"vault","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"weth","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"withdrawAllToVault","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"withdrawToVault","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}],"constant":false}]
              

Contract Creation Code

Verify & Publish
0x60806040523480156200001157600080fd5b50604080517f656970313936372e676f7665726e61626c65496e69742e73746f7261676500008152905190819003601e0190207fa7ec62784904ff31cbcc32d09932a58e7f1e4476e1d041995b37c917990b16dc600019909101146200007357fe5b600160405180806200512e602291396022019050604051809103902060001c0360001b7fa1709211eeccf8f4ad5b6700d52a1a9525b5f5ae1e9e5f9e5a0c2fc23c86e53060001b14620000c257fe5b604080517f656970313936372e737472617465677953746f726167652e7661756c740000008152905190819003601d0190207fefd7c7d9ef1040fc87e7ad11fe15f86e1d11e1df03c6d7c87f7e1f4041f08d41600019909101146200012357fe5b600160405180806200522a602391396023019050604051809103902060001c0360001b7fdae0aafd977983cb1e78d8f638900ff361dc3c48c43118ca1dd77d1af3f47bbf60001b146200017257fe5b600160405180806200505d602291396022019050604051809103902060001c0360001b7f3d9bb16e77837e25cada0cf894835418b38e8e18fbec6cfd192eb344bebfa6b860001b14620001c157fe5b6001604051808062005209602191396021019050604051809103902060001c0360001b7fc403216a7704d160f6a3b5c3b149a1226a6080f0a5dd27b27d9ba9c022fa0afc60001b146200021057fe5b604080517f656970313936372e737472617465677953746f726167652e73656c6c000000008152905190819003601c0190207f656de32df98753b07482576beb0d00a6b949ebf84c066c765f54f26725221bb6600019909101146200027157fe5b6001604051808062005107602791396027019050604051809103902060001c0360001b7fa07a20a2d463a602c2b891eb35f244624d9068572811f63d0e094072fb54591a60001b14620002c057fe5b600160405180806200524d602e9139602e019050604051809103902060001c0360001b7fe3ee74fb7893020b457d8071ed1ef76ace2bf4903abd7b24d3ce312e9c72c02960001b146200030f57fe5b6001604051808062004fdf603091396030019050604051809103902060001c0360001b7f0286fd414602b432a8c80a0125e9a25de9bba96da9d5068c832ff73f09208a3b60001b146200035e57fe5b6001604051808062005033602a9139602a019050604051809103902060001c0360001b7f29f7fcd4fe2517c1963807a1ec27b0e45e67c60a874d5eeac7a0b1ab1bb8444760001b14620003ad57fe5b60016040518080620050a5603391396033019050604051809103902060001c0360001b7f414c5263b05428f1be1bfa98e25407cc78dd031d0d3cd2a2e3d63b488804f22e60001b14620003fc57fe5b60016040518080620050d8602f9139602f019050604051809103902060001c0360001b7f82b330ca72bcd6db11a26f10ce47ebcfe574a9c646bccbc6f1cd4478eae16b3160001b146200044b57fe5b60016040518080620051c1602791396027019050604051809103902060001c0360001b7fbc7c0d42a71b75c3129b337a259c346200f901408f273707402da4b51db3b8e760001b146200049a57fe5b604080517f656970313936372e737472617465677953746f726167652e6d756c7469536967815290519081900360200190207f3e9de78b54c338efbc04e3a091b87dc7efb5d7024738302c548fc59fba1c34e660001990910114620004fb57fe5b604080517f656970313936372e737472617465677953746f726167652e706f6f6c496400008152905190819003601e0190207f3fd729bfa2e28b7806b03a6e014729f59477b530f995be4d51defc9dad94810b600019909101146200055c57fe5b600160405180806200500f602491396024019050604051809103902060001c0360001b7f219270253dbc530471c88a9e7c321b36afda219583431e7b6c386d2d46e70c8660001b14620005ab57fe5b600160405180806200507f602691396026019050604051809103902060001c0360001b7f414478d5ad7f54ead8a3dd018bba4f8d686ba5ab5975cd376e0c98f98fb713c560001b14620005fa57fe5b6001604051808062005195602c9139602c019050604051809103902060001c0360001b7fb7c50ef998211fff3420379d0bf5b8dfb0cee909d1b7d9e517f311c104675b0960001b146200064957fe5b6001604051808062005150602491396024019050604051809103902060001c0360001b7fb306bb7adebd5a22f5e4cdf1efa00bc5f62d4f5554ef9d62c1b16327cd3ab5f960001b146200069857fe5b6001604051808062005174602191396021019050604051809103902060001c0360001b7fb487e573671f10704ed229d25cf38dda6d287a35872859d096c0395110a0adb160001b14620006e757fe5b60016040518080620051e8602191396021019050604051809103902060001c0360001b7fc26d330f887c749cb38ae7c37873ff08ac4bba7aec9113c82d48a0cf6cc145f260001b146200073657fe5b61489980620007466000396000f3fe608060405234801561001057600080fd5b506004361061038e5760003560e01c80638eab5923116101de578063c6def0761161010f578063eb3e4961116100ad578063f77c47911161007c578063f77c4791146109e5578063f7c618c1146109ed578063fbfa77cf146109f5578063fdf5272d146109fd5761038e565b8063eb3e496114610977578063ec5a61ae1461097f578063ed0c873e146109ab578063f04abcd0146109c85761038e565b8063d0aeb429116100e9578063d0aeb4291461086b578063d3df8aa41461090c578063db62048514610914578063e72f33f81461091c5761038e565b8063c6def0761461083e578063c89039c514610846578063ce8c42e81461084e5761038e565b8063b076a53a1161017c578063bf809e1f11610156578063bf809e1f14610800578063bfd131f114610808578063c2a2a07b14610810578063c4d66de8146108185761038e565b8063b076a53a146107bc578063b60f151a146107db578063ba09591e146107e35761038e565b80639bb00442116101b85780639bb00442146106d05780639d16acfd14610781578063a1dab23e146107ac578063a8365693146107b45761038e565b80638eab59231461069a5780639137c1a7146106a25780639a508c8e146106c85761038e565b806345d01e4a116102c357806366666aa9116102615780637bb7bed1116102305780637bb7bed11461064757806382de9c1b1461066457806385b97b6f1461066c578063887ee971146106925761038e565b806366666aa91461058e57806366f6e531146105965780636f307dc31461059e5780637484192d146105a65761038e565b8063501859461161029d57806350185946146105505780635641ec0314610576578063596fa9e31461057e5780635aa6e675146105865761038e565b806345d01e4a146105125780634d352ab21461051a5780634fa5d854146105485761038e565b80632e1e04621161033057806337c84e131161030a57806337c84e13146104f25780633e0dc34e146104fa5780633fc8cef314610502578063457100741461050a5761038e565b80632e1e0462146104da5780632ea19326146104e257806336e0004a146104ea5761038e565b80630c80447a1161036c5780630c80447a1461043c5780630dff5c31146104625780631113ef521461049c578063183e9565146104d25761038e565b8063026a0dd01461039357806305191794146103ad57806309ff18f014610418575b600080fd5b61039b610a05565b60408051918252519081900360200190f35b61041660048036036101408110156103c457600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101358216916080820135169060a08101359060c08101359060e0810135151590610100810135906101200135610a36565b005b610420610b46565b604080516001600160a01b039092168252519081900360200190f35b6104166004803603602081101561045257600080fd5b50356001600160a01b0316610b71565b6104886004803603602081101561047857600080fd5b50356001600160a01b0316610c68565b604080519115158252519081900360200190f35b610416600480360360608110156104b257600080fd5b506001600160a01b03813581169160208101359091169060400135610c7d565b610420610e35565b610420610e4d565b61039b610e65565b610420610e6b565b61039b610e96565b61039b610ec1565b610420610eec565b610488610f04565b61039b610f2f565b6104166004803603604081101561053057600080fd5b506001600160a01b038135811691602001351661105d565b6104166112dc565b6104886004803603602081101561056657600080fd5b50356001600160a01b0316611429565b610416611493565b610420611570565b610420611588565b6104206115fb565b61039b611626565b610420611651565b610416600480360360208110156105bc57600080fd5b810190602081018135600160201b8111156105d657600080fd5b8201836020820111156105e857600080fd5b803590602001918460208302840111600160201b8311171561060957600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092955061167c945050505050565b6104206004803603602081101561065d57600080fd5b503561185a565b61039b611881565b6104166004803603602081101561068257600080fd5b50356001600160a01b03166118ac565b6104206119a1565b6104886119cc565b610416600480360360208110156106b857600080fd5b50356001600160a01b03166119f7565b610416611b26565b610416600480360360408110156106e657600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111561071057600080fd5b82018360208201111561072257600080fd5b803590602001918460208302840111600160201b8311171561074357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611c21945050505050565b610789611e45565b6040805192151583526001600160a01b0390911660208301528051918290030190f35b61039b611e91565b61039b611ebc565b610416600480360360208110156107d257600080fd5b50351515611ee7565b61039b611fbb565b610416600480360360208110156107f957600080fd5b5035611fe6565b6104206120ba565b6104166120e5565b61048861225c565b6104166004803603602081101561082e57600080fd5b50356001600160a01b0316612261565b61042061230c565b610420612324565b6104166004803603602081101561086457600080fd5b503561234f565b6104166004803603602081101561088157600080fd5b810190602081018135600160201b81111561089b57600080fd5b8201836020820111156108ad57600080fd5b803590602001918460208302840111600160201b831117156108ce57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506124ca945050505050565b61048861270c565b610416612737565b610416600480360361010081101561093357600080fd5b506001600160a01b03813581169160208101358216916040820135811691606081013582169160808201359160a081013582169160c08201359160e001351661280c565b610420612aa7565b6104206004803603604081101561099557600080fd5b506001600160a01b038135169060200135612ab6565b610416600480360360208110156109c157600080fd5b5035612aeb565b610420600480360360208110156109de57600080fd5b5035612be0565b610420612bed565b610420612c2f565b610420612c5a565b610420612c85565b6000610a307f0286fd414602b432a8c80a0125e9a25de9bba96da9d5068c832ff73f09208a3b612cac565b90505b90565b600054610100900460ff1680610a4f5750610a4f612cb0565b80610a5d575060005460ff16155b610a985760405162461bcd60e51b815260040180806020018281038252602e81526020018061477f602e913960400191505060405180910390fd5b600054610100900460ff16158015610ac3576000805460ff1961ff0019909116610100171660011790555b610acc8b612261565b610ad58a612cb6565b610ade89612ce0565b610ae788612d0a565b610af087612d34565b610af986612d5e565b610b0285612d88565b610b0b84612db2565b610b1483612ddc565b610b1d82612e06565b610b276000612e30565b8015610b39576000805461ff00191690555b5050505050505050505050565b6000610a307f29f7fcd4fe2517c1963807a1ec27b0e45e67c60a874d5eeac7a0b1ab1bb84447612cac565b610b79612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610bce57600080fd5b505afa158015610be2573d6000803e3d6000fd5b505050506040513d6020811015610bf857600080fd5b5051610c3c576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b610c4581612e7f565b610c65610c60610c53611ebc565b429063ffffffff612ea916565b612f0a565b50565b60356020526000908152604090205460ff1681565b610c85612e5a565b6001600160a01b031663b429afeb336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610cda57600080fd5b505afa158015610cee573d6000803e3d6000fd5b505050506040513d6020811015610d0457600080fd5b505180610d965750610d14612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610d6957600080fd5b505afa158015610d7d573d6000803e3d6000fd5b505050506040513d6020811015610d9357600080fd5b50515b610dd15760405162461bcd60e51b815260040180806020018281038252602b81526020018061464e602b913960400191505060405180910390fd5b610dda82611429565b15610e165760405162461bcd60e51b81526004018080602001828103825260228152602001806146796022913960400191505060405180910390fd5b610e306001600160a01b038316848363ffffffff612f3416565b505050565b73f49440c1f012d041802b25a73e5b0b9166a75c0281565b73d9e1ce17f2641f24ae83637ab66a2cca9c378b9f81565b61271081565b6000610a307f3e9de78b54c338efbc04e3a091b87dc7efb5d7024738302c548fc59fba1c34e6612cac565b6000610a307fb7c50ef998211fff3420379d0bf5b8dfb0cee909d1b7d9e517f311c104675b09612cac565b6000610a307f3fd729bfa2e28b7806b03a6e014729f59477b530f995be4d51defc9dad94810b612cac565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6000610a307f656de32df98753b07482576beb0d00a6b949ebf84c066c765f54f26725221bb6612f86565b6000610a30610f3c611651565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610f9157600080fd5b505afa158015610fa5573d6000803e3d6000fd5b505050506040513d6020811015610fbb57600080fd5b5051611051610fc86120ba565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561101d57600080fd5b505afa158015611031573d6000803e3d6000fd5b505050506040513d602081101561104757600080fd5b5051611051612f9a565b9063ffffffff612ea916565b600054610100900460ff16806110765750611076612cb0565b80611084575060005460ff16155b6110bf5760405162461bcd60e51b815260040180806020018281038252602e81526020018061477f602e913960400191505060405180910390fd5b600054610100900460ff161580156110ea576000805460ff1961ff0019909116610100171660011790555b735b5cfe992adac0c9d48e05854b2d91c73a00385873353e489311b21355461353fec2d02b73ef0ede7f73d533a949740bb3306d119cc777fa900ba034cd52734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b736b175474e89094c44da98b954eedeac495271d0f7309672362833d8f703d5395ef3252d4bfa51c15ca61117a89878a88600b8760018861280c565b6040805180820182526001600160a01b03861680825273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2602080840191909152600091825260349052919091206111c69160026145a6565b506040805180820182526001600160a01b03851680825273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2602080840191909152600091825260349052919091206112139160026145a6565b506040805180820190915273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281526001600160a01b03831660208201526112529060339060026145a6565b50604080518082019091526001600160a01b0380861682528416602082015261127f9060369060026145a6565b50506001600160a01b03928316600090815260356020526040808220805460ff1990811690915593851682528082208054851690559190931683529091208054909116905550508015610e30576000805461ff0019169055505050565b6112e461270c565b156113205760405162461bcd60e51b81526004018080602001828103825260348152602001806148316034913960400191505060405180910390fd5b611328612c5a565b6001600160a01b0316336001600160a01b0316148061135f575061134a612bed565b6001600160a01b0316336001600160a01b0316145b80611382575061136d611588565b6001600160a01b0316336001600160a01b0316145b6113bd5760405162461bcd60e51b815260040180806020018281038252603981526020018061469b6039913960400191505060405180910390fd5b6113c56115fb565b6001600160a01b0316633d18b9126040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156113ff57600080fd5b505af1158015611413573d6000803e3d6000fd5b5050505061141f612ff9565b6114276137bb565b565b6000611433612c2f565b6001600160a01b0316826001600160a01b0316148061146a5750611455611651565b6001600160a01b0316826001600160a01b0316145b8061148d57506114786120ba565b6001600160a01b0316826001600160a01b0316145b92915050565b61149b612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156114f057600080fd5b505afa158015611504573d6000803e3d6000fd5b505050506040513d602081101561151a57600080fd5b505161155e576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b611566613898565b6114276001612e30565b737a250d5630b4cf539739df2c5dacb4c659f2488d81565b6000611592612e5a565b6001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b1580156115ca57600080fd5b505afa1580156115de573d6000803e3d6000fd5b505050506040513d60208110156115f457600080fd5b5051905090565b6000610a307f3d9bb16e77837e25cada0cf894835418b38e8e18fbec6cfd192eb344bebfa6b8612cac565b6000610a307fb487e573671f10704ed229d25cf38dda6d287a35872859d096c0395110a0adb1612cac565b6000610a307fa1709211eeccf8f4ad5b6700d52a1a9525b5f5ae1e9e5f9e5a0c2fc23c86e530612cac565b611684612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156116d957600080fd5b505afa1580156116ed573d6000803e3d6000fd5b505050506040513d602081101561170357600080fd5b5051611747576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168160008151811061177257fe5b60200260200101516001600160a01b0316146117d5576040805162461bcd60e51b815260206004820152601b60248201527f506174682073686f756c64207374617274207769746820574554480000000000604482015290519081900360640190fd5b6117dd612324565b6001600160a01b0316816001835103815181106117f657fe5b60200260200101516001600160a01b0316146118435760405162461bcd60e51b81526004018080602001828103825260218152602001806146f86021913960400191505060405180910390fd5b80516118569060339060208401906145a6565b5050565b6036818154811061186757fe5b6000918252602090912001546001600160a01b0316905081565b6000610a307f414c5263b05428f1be1bfa98e25407cc78dd031d0d3cd2a2e3d63b488804f22e612cac565b6118b4612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561190957600080fd5b505afa15801561191d573d6000803e3d6000fd5b505050506040513d602081101561193357600080fd5b5051611977576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b610c657fc26d330f887c749cb38ae7c37873ff08ac4bba7aec9113c82d48a0cf6cc145f282613a1c565b6000610a307fb306bb7adebd5a22f5e4cdf1efa00bc5f62d4f5554ef9d62c1b16327cd3ab5f9612cac565b6000610a307fbc7c0d42a71b75c3129b337a259c346200f901408f273707402da4b51db3b8e7612f86565b6119ff612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611a5457600080fd5b505afa158015611a68573d6000803e3d6000fd5b505050506040513d6020811015611a7e57600080fd5b5051611ac2576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b6001600160a01b038116611b1d576040805162461bcd60e51b815260206004820152601e60248201527f6e65772073746f726167652073686f756c646e277420626520656d7074790000604482015290519081900360640190fd5b610c6581613a20565b611b2e612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611b8357600080fd5b505afa158015611b97573d6000803e3d6000fd5b505050506040513d6020811015611bad57600080fd5b5051611bf1576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b611bf9613a44565b611c1673f49440c1f012d041802b25a73e5b0b9166a75c026118ac565b6114276103e8612aeb565b611c29612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611c7e57600080fd5b505afa158015611c92573d6000803e3d6000fd5b505050506040513d6020811015611ca857600080fd5b5051611cec576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031681600183510381518110611d1a57fe5b60200260200101516001600160a01b031614611d79576040805162461bcd60e51b81526020600482015260196024820152780a0c2e8d040e6d0deead8c840cadcc840eed2e8d040ae8aa89603b1b604482015290519081900360640190fd5b816001600160a01b031681600081518110611d9057fe5b60200260200101516001600160a01b031614611ddd5760405162461bcd60e51b815260040180806020018281038252602281526020018061473c6022913960400191505060405180910390fd5b60368054600181019091557f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b80180546001600160a01b0319166001600160a01b03841690811790915560009081526034602090815260409091208251610e30928401906145a6565b600080611e50611881565b15801590611e645750611e61611881565b42115b8015611e8157506000611e75610b46565b6001600160a01b031614155b611e89610b46565b915091509091565b6000610a307fc403216a7704d160f6a3b5c3b149a1226a6080f0a5dd27b27d9ba9c022fa0afc612cac565b6000610a307f82b330ca72bcd6db11a26f10ce47ebcfe574a9c646bccbc6f1cd4478eae16b31612cac565b611eef612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611f4457600080fd5b505afa158015611f58573d6000803e3d6000fd5b505050506040513d6020811015611f6e57600080fd5b5051611fb2576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b610c6581612db2565b6000610a307fe3ee74fb7893020b457d8071ed1ef76ace2bf4903abd7b24d3ce312e9c72c029612cac565b611fee612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561204357600080fd5b505afa158015612057573d6000803e3d6000fd5b505050506040513d602081101561206d57600080fd5b50516120b1576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b610c6581612ddc565b6000610a307f414478d5ad7f54ead8a3dd018bba4f8d686ba5ab5975cd376e0c98f98fb713c5612cac565b6120ed612c5a565b6001600160a01b0316336001600160a01b03161480612124575061210f612bed565b6001600160a01b0316336001600160a01b0316145b806121475750612132611588565b6001600160a01b0316336001600160a01b0316145b6121825760405162461bcd60e51b815260040180806020018281038252603981526020018061469b6039913960400191505060405180910390fd5b600061218c6115fb565b6001600160a01b0316146121a2576121a2613a58565b6121aa612ff9565b6114276121b5612c5a565b6121bd611651565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561221257600080fd5b505afa158015612226573d6000803e3d6000fd5b505050506040513d602081101561223c57600080fd5b5051612246611651565b6001600160a01b0316919063ffffffff612f3416565b600190565b600054610100900460ff168061227a575061227a612cb0565b80612288575060005460ff16155b6122c35760405162461bcd60e51b815260040180806020018281038252602e81526020018061477f602e913960400191505060405180910390fd5b600054610100900460ff161580156122ee576000805460ff1961ff0019909116610100171660011790555b6122f782613abc565b8015611856576000805461ff00191690555050565b73f403c135812408bfbe8713b5a23a04b3d48aae3181565b6000610a307f219270253dbc530471c88a9e7c321b36afda219583431e7b6c386d2d46e70c86612cac565b612357612c5a565b6001600160a01b0316336001600160a01b0316148061238e5750612379612bed565b6001600160a01b0316336001600160a01b0316145b806123b1575061239c611588565b6001600160a01b0316336001600160a01b0316145b6123ec5760405162461bcd60e51b815260040180806020018281038252603981526020018061469b6039913960400191505060405180910390fd5b60006123f6611651565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561244b57600080fd5b505afa15801561245f573d6000803e3d6000fd5b505050506040513d602081101561247557600080fd5b50519050808211156124b6576000612493838363ffffffff613b5216565b905060006124a86124a2612f9a565b83613b94565b90506124b381613baa565b50505b6118566124c1612c5a565b83612246611651565b6124d2612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561252757600080fd5b505afa15801561253b573d6000803e3d6000fd5b505050506040513d602081101561255157600080fd5b5051612595576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316816001835103815181106125c357fe5b60200260200101516001600160a01b031614612622576040805162461bcd60e51b81526020600482015260196024820152780a0c2e8d040e6d0deead8c840cadcc840eed2e8d040ae8aa89603b1b604482015290519081900360640190fd5b6000805b603654811015612682576036818154811061263d57fe5b600091825260208220015484516001600160a01b0390911691859161265e57fe5b60200260200101516001600160a01b0316141561267a57600191505b600101612626565b50806126bf5760405162461bcd60e51b815260040180806020018281038252602481526020018061480d6024913960400191505060405180910390fd5b8160346000846000815181106126d157fe5b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000209080519060200190610e309291906145a6565b6000610a307fa07a20a2d463a602c2b891eb35f244624d9068572811f63d0e094072fb54591a612f86565b61273f612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561279457600080fd5b505afa1580156127a8573d6000803e3d6000fd5b505050506040513d60208110156127be57600080fd5b5051612802576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b6114276000612e30565b600054610100900460ff16806128255750612825612cb0565b80612833575060005460ff16155b61286e5760405162461bcd60e51b815260040180806020018281038252602e81526020018061477f602e913960400191505060405180910390fd5b600054610100900460ff16158015612899576000805460ff1961ff0019909116610100171660011790555b6128ce8989898973c02aaa39b223fe8d0a0e5c4f27ead9083c756cc261012c6103e86001670de0b6b3a764000061a8c0610a36565b60008073f403c135812408bfbe8713b5a23a04b3d48aae316001600160a01b0316631526fe27886040518263ffffffff1660e01b81526004018082815260200191505060c06040518083038186803b15801561292957600080fd5b505afa15801561293d573d6000803e3d6000fd5b505050506040513d60c081101561295357600080fd5b5080516020909101519092509050612969611651565b6001600160a01b0316826001600160a01b0316146129b85760405162461bcd60e51b81526004018080602001828103825260238152602001806147196023913960400191505060405180910390fd5b600485106129f75760405162461bcd60e51b81526004018080602001828103825260248152602001806146d46024913960400191505060405180910390fd5b612a0085613c04565b612a0987613c2e565b612a1286613c58565b612a1b81613c82565b612a2484613cac565b612a2f6103e8612aeb565b612a4c73f49440c1f012d041802b25a73e5b0b9166a75c026118ac565b6040805160008152602081019182905251612a69916033916145a6565b506040805160008152602081019182905251612a87916036916145a6565b5050508015612a9c576000805461ff00191690555b505050505050505050565b6037546001600160a01b031681565b60346020528160005260406000208181548110612acf57fe5b6000918252602090912001546001600160a01b03169150829050565b612af3612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015612b4857600080fd5b505afa158015612b5c573d6000803e3d6000fd5b505050506040513d6020811015612b7257600080fd5b5051612bb6576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b610c657fb487e573671f10704ed229d25cf38dda6d287a35872859d096c0395110a0adb182613a1c565b6033818154811061186757fe5b6000612bf7612e5a565b6001600160a01b031663f77c47916040518163ffffffff1660e01b815260040160206040518083038186803b1580156115ca57600080fd5b6000610a307fdae0aafd977983cb1e78d8f638900ff361dc3c48c43118ca1dd77d1af3f47bbf612cac565b6000610a307fefd7c7d9ef1040fc87e7ad11fe15f86e1d11e1df03c6d7c87f7e1f4041f08d41612cac565b6000610a307fc26d330f887c749cb38ae7c37873ff08ac4bba7aec9113c82d48a0cf6cc145f25b5490565b303b1590565b610c657fa1709211eeccf8f4ad5b6700d52a1a9525b5f5ae1e9e5f9e5a0c2fc23c86e53082613a1c565b610c657fefd7c7d9ef1040fc87e7ad11fe15f86e1d11e1df03c6d7c87f7e1f4041f08d4182613a1c565b610c657f3d9bb16e77837e25cada0cf894835418b38e8e18fbec6cfd192eb344bebfa6b882613a1c565b610c657fdae0aafd977983cb1e78d8f638900ff361dc3c48c43118ca1dd77d1af3f47bbf82613a1c565b610c657fe3ee74fb7893020b457d8071ed1ef76ace2bf4903abd7b24d3ce312e9c72c02982613a1c565b610c657f0286fd414602b432a8c80a0125e9a25de9bba96da9d5068c832ff73f09208a3b82613a1c565b610c657f656de32df98753b07482576beb0d00a6b949ebf84c066c765f54f26725221bb682613cd6565b610c657fc403216a7704d160f6a3b5c3b149a1226a6080f0a5dd27b27d9ba9c022fa0afc82613a1c565b610c657f82b330ca72bcd6db11a26f10ce47ebcfe574a9c646bccbc6f1cd4478eae16b3182613a1c565b610c657fa07a20a2d463a602c2b891eb35f244624d9068572811f63d0e094072fb54591a82613cd6565b7fa7ec62784904ff31cbcc32d09932a58e7f1e4476e1d041995b37c917990b16dc5490565b610c657f29f7fcd4fe2517c1963807a1ec27b0e45e67c60a874d5eeac7a0b1ab1bb8444782613a1c565b600082820183811015612f03576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b610c657f414c5263b05428f1be1bfa98e25407cc78dd031d0d3cd2a2e3d63b488804f22e82613a1c565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610e30908490613cf1565b6000612f9182612cac565b60011492915050565b6000612fa46115fb565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156115ca57600080fd5b613001610f04565b61304c577f408a4b113351e616bb41bad991f29bbad84b43c3810e7492a6bc7c6388dfe0c261302e610f04565b604080519115158252600060208301528051918290030190a1611427565b60005b6036548110156133d15760006036828154811061306857fe5b6000918252602080832090910154604080516370a0823160e01b815230600482015290516001600160a01b03909216945084926370a0823192602480840193829003018186803b1580156130bb57600080fd5b505afa1580156130cf573d6000803e3d6000fd5b505050506040513d60208110156130e557600080fd5b5051905080158061310e57506001600160a01b0382166000908152603460205260409020546002115b1561311a5750506133c9565b600061314661271061313a61312d611626565b859063ffffffff613eaf16565b9063ffffffff613f0816565b9050801561318f57613170613159612c85565b6001600160a01b038516908363ffffffff612f3416565b613180828263ffffffff613b5216565b91508161318f575050506133c9565b6001600160a01b03831660009081526035602052604081205460ff16156131cb5750737a250d5630b4cf539739df2c5dacb4c659f2488d6131e2565b5073d9e1ce17f2641f24ae83637ab66a2cca9c378b9f5b6131fd6001600160a01b03851682600063ffffffff613f4a16565b6132176001600160a01b038516828563ffffffff613f4a16565b806001600160a01b03166338ed173984600160346000896001600160a01b03166001600160a01b0316815260200190815260200160002030426040518663ffffffff1660e01b81526004018086815260200185815260200180602001846001600160a01b03166001600160a01b0316815260200183815260200182810382528581815481526020019150805480156132d857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116132ba575b50509650505050505050600060405180830381600087803b1580156132fc57600080fd5b505af1158015613310573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561333957600080fd5b8101908080516040519392919084600160201b82111561335857600080fd5b90830190602082018581111561336d57600080fd5b82518660208202830111600160201b8211171561338957600080fd5b82525081516020918201928201910280838360005b838110156133b657818101518382015260200161339e565b5050505090500160405250505050505050505b60010161304f565b50604080516370a0823160e01b8152306004820152905160009173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2916370a0823191602480820192602092909190829003018186803b15801561342757600080fd5b505afa15801561343b573d6000803e3d6000fd5b505050506040513d602081101561345157600080fd5b5051905061345e8161405d565b6000613468612c2f565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156134bd57600080fd5b505afa1580156134d1573d6000803e3d6000fd5b505050506040513d60208110156134e757600080fd5b50519050806134f7575050611427565b600060356000613505612324565b6001600160a01b0316815260208101919091526040016000205460ff16156135425750737a250d5630b4cf539739df2c5dacb4c659f2488d613559565b5073d9e1ce17f2641f24ae83637ab66a2cca9c378b9f5b61357d816000613567612c2f565b6001600160a01b0316919063ffffffff613f4a16565b61358a8183613567612c2f565b600060019050816001600160a01b03166338ed17398483603330426040518663ffffffff1660e01b81526004018086815260200185815260200180602001846001600160a01b03166001600160a01b03168152602001838152602001828103825285818154815260200191508054801561362d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161360f575b50509650505050505050600060405180830381600087803b15801561365157600080fd5b505af1158015613665573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561368e57600080fd5b8101908080516040519392919084600160201b8211156136ad57600080fd5b9083019060208201858111156136c257600080fd5b82518660208202830111600160201b821117156136de57600080fd5b82525081516020918201928201910280838360005b8381101561370b5781810151838201526020016136f3565b50505050905001604052505050506000613723612324565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561377857600080fd5b505afa15801561378c573d6000803e3d6000fd5b505050506040513d60208110156137a257600080fd5b5051905080156137b4576137b46141b5565b5050505050565b6137c361270c565b156137ff5760405162461bcd60e51b81526004018080602001828103825260348152602001806148316034913960400191505060405180910390fd5b6000613809611651565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561385e57600080fd5b505afa158015613872573d6000803e3d6000fd5b505050506040513d602081101561388857600080fd5b5051111561142757611427614325565b60006138a2612f9a565b90508015613915576138b26115fb565b6001600160a01b0316631c1c6fe560006040518263ffffffff1660e01b81526004018082151515158152602001915050600060405180830381600087803b1580156138fc57600080fd5b505af1158015613910573d6000803e3d6000fd5b505050505b600061391f6120ba565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561397457600080fd5b505afa158015613988573d6000803e3d6000fd5b505050506040513d602081101561399e57600080fd5b5051905080156118565773f403c135812408bfbe8713b5a23a04b3d48aae3163958e2d316139ca610ec1565b6040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015613a0057600080fd5b505af1158015613a14573d6000803e3d6000fd5b505050505050565b9055565b7fa7ec62784904ff31cbcc32d09932a58e7f1e4476e1d041995b37c917990b16dc55565b613a4e6000612e7f565b6114276000612f0a565b6000613a62612f9a565b9050801561391557613a726115fb565b6001600160a01b0316631c1c6fe560016040518263ffffffff1660e01b81526004018082151515158152602001915050600060405180830381600087803b1580156138fc57600080fd5b600054610100900460ff1680613ad55750613ad5612cb0565b80613ae3575060005460ff16155b613b1e5760405162461bcd60e51b815260040180806020018281038252602e81526020018061477f602e913960400191505060405180910390fd5b600054610100900460ff16158015613b49576000805460ff1961ff0019909116610100171660011790555b6122f782613a20565b6000612f0383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061446e565b6000818310613ba35781612f03565b5090919050565b613bb26115fb565b6001600160a01b03166338d074368260006040518363ffffffff1660e01b8152600401808381526020018215151515815260200192505050600060405180830381600087803b1580156138fc57600080fd5b610c657fb7c50ef998211fff3420379d0bf5b8dfb0cee909d1b7d9e517f311c104675b0982613a1c565b610c657f3fd729bfa2e28b7806b03a6e014729f59477b530f995be4d51defc9dad94810b82613a1c565b610c657f219270253dbc530471c88a9e7c321b36afda219583431e7b6c386d2d46e70c8682613a1c565b610c657f414478d5ad7f54ead8a3dd018bba4f8d686ba5ab5975cd376e0c98f98fb713c582613a1c565b610c657fb306bb7adebd5a22f5e4cdf1efa00bc5f62d4f5554ef9d62c1b16327cd3ab5f982613a1c565b6118568282613ce6576000613ce9565b60015b60ff16613a1c565b613d03826001600160a01b0316614505565b613d54576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310613d925780518252601f199092019160209182019101613d73565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613df4576040519150601f19603f3d011682016040523d82523d6000602084013e613df9565b606091505b509150915081613e50576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115613ea957808060200190516020811015613e6c57600080fd5b5051613ea95760405162461bcd60e51b815260040180806020018281038252602a8152602001806147ad602a913960400191505060405180910390fd5b50505050565b600082613ebe5750600061148d565b82820282848281613ecb57fe5b0414612f035760405162461bcd60e51b815260040180806020018281038252602181526020018061475e6021913960400191505060405180910390fd5b6000612f0383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614541565b801580613fd0575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b158015613fa257600080fd5b505afa158015613fb6573d6000803e3d6000fd5b505050506040513d6020811015613fcc57600080fd5b5051155b61400b5760405162461bcd60e51b81526004018080602001828103825260368152602001806147d76036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610e30908490613cf1565b801561417357600061407b614070610a05565b61313a61312d611fbb565b6040805184815260208101839052428183015290519192507f33fd2845a0f10293482de360244dd4ad31ddbb4b8c4a1ded3875cf8ebfba184b919081900360600190a16140d36140c9612bed565b6000613567612c2f565b6140e76140de612bed565b82613567612c2f565b6140ef612bed565b6001600160a01b031663f706bf28614105612c2f565b836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561415557600080fd5b505af1158015614169573d6000803e3d6000fd5b5050505050610c65565b6040805160008082526020820152428183015290517f33fd2845a0f10293482de360244dd4ad31ddbb4b8c4a1ded3875cf8ebfba184b9181900360600190a150565b60006141bf612324565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561421457600080fd5b505afa158015614228573d6000803e3d6000fd5b505050506040513d602081101561423e57600080fd5b5051905061425761424d6119a1565b6000613567612324565b61426b6142626119a1565b82613567612324565b61427361460b565b818161427d610e96565b6004811061428757fe5b602002015260006142966119a1565b6001600160a01b031663029b2f3483836040518363ffffffff1660e01b81526004018083600460200280838360005b838110156142dd5781810151838201526020016142c5565b5050505090500182815260200192505050600060405180830381600087803b15801561430857600080fd5b505af115801561431c573d6000803e3d6000fd5b50505050505050565b600061432f611651565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561438457600080fd5b505afa158015614398573d6000803e3d6000fd5b505050506040513d60208110156143ae57600080fd5b505190506143d473f403c135812408bfbe8713b5a23a04b3d48aae316000613567611651565b6143f573f403c135812408bfbe8713b5a23a04b3d48aae3182613567611651565b73f403c135812408bfbe8713b5a23a04b3d48aae316360759fce614417610ec1565b60016040518363ffffffff1660e01b8152600401808381526020018215151515815260200192505050600060405180830381600087803b15801561445a57600080fd5b505af11580156137b4573d6000803e3d6000fd5b600081848411156144fd5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156144c25781810151838201526020016144aa565b50505050905090810190601f1680156144ef5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061453957508115155b949350505050565b600081836145905760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156144c25781810151838201526020016144aa565b50600083858161459c57fe5b0495945050505050565b8280548282559060005260206000209081019282156145fb579160200282015b828111156145fb57825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906145c6565b50614607929150614629565b5090565b60405180608001604052806004906020820280388339509192915050565b610a3391905b808211156146075780546001600160a01b031916815560010161462f56fe5468652063616c6c6572206d75737420626520636f6e74726f6c6c6572206f7220676f7665726e616e6365746f6b656e20697320646566696e6564206173206e6f742073616c76616761626c655468652073656e6465722068617320746f2062652074686520636f6e74726f6c6c65722c20676f7665726e616e63652c206f72207661756c744465706f73697420617272617920706f736974696f6e206f7574206f6620626f756e6473506174682073686f756c6420656e642077697468206465706f736974546f6b656e506f6f6c20496e666f20646f6573206e6f74206d6174636820756e6465726c79696e67506174682073686f756c64207374617274207769746820726577617264546f6b656e536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a65645361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365506174682073686f756c642073746172742077697468206120726577617264546f6b656e416374696f6e20626c6f636b65642061732074686520737472617465677920697320696e20656d657267656e6379207374617465a265627a7a72315820238985b22045a94951a92753734aa6858ca279011ea88d38e8d3b92781e3239164736f6c63430005100032656970313936372e737472617465677953746f726167652e70726f66697453686172696e6744656e6f6d696e61746f72656970313936372e737472617465677953746f726167652e6465706f736974546f6b656e656970313936372e737472617465677953746f726167652e6e657874496d706c656d656e746174696f6e656970313936372e737472617465677953746f726167652e726577617264506f6f6c656970313936372e737472617465677953746f726167652e6465706f73697452656365697074656970313936372e737472617465677953746f726167652e6e657874496d706c656d656e746174696f6e54696d657374616d70656970313936372e737472617465677953746f726167652e6e657874496d706c656d656e746174696f6e44656c6179656970313936372e737472617465677953746f726167652e706175736564496e76657374696e67656970313936372e737472617465677953746f726167652e756e6465726c79696e67656970313936372e737472617465677953746f726167652e63757276654465706f736974656970313936372e737472617465677953746f726167652e686f646c526174696f656970313936372e737472617465677953746f726167652e6465706f7369744172726179506f736974696f6e656970313936372e737472617465677953746f726167652e726577617264436c61696d61626c65656970313936372e737472617465677953746f726167652e686f646c5661756c74656970313936372e737472617465677953746f726167652e73656c6c466c6f6f72656970313936372e737472617465677953746f726167652e726577617264546f6b656e656970313936372e737472617465677953746f726167652e70726f66697453686172696e674e756d657261746f72

Deployed ByteCode

0x608060405234801561001057600080fd5b506004361061038e5760003560e01c80638eab5923116101de578063c6def0761161010f578063eb3e4961116100ad578063f77c47911161007c578063f77c4791146109e5578063f7c618c1146109ed578063fbfa77cf146109f5578063fdf5272d146109fd5761038e565b8063eb3e496114610977578063ec5a61ae1461097f578063ed0c873e146109ab578063f04abcd0146109c85761038e565b8063d0aeb429116100e9578063d0aeb4291461086b578063d3df8aa41461090c578063db62048514610914578063e72f33f81461091c5761038e565b8063c6def0761461083e578063c89039c514610846578063ce8c42e81461084e5761038e565b8063b076a53a1161017c578063bf809e1f11610156578063bf809e1f14610800578063bfd131f114610808578063c2a2a07b14610810578063c4d66de8146108185761038e565b8063b076a53a146107bc578063b60f151a146107db578063ba09591e146107e35761038e565b80639bb00442116101b85780639bb00442146106d05780639d16acfd14610781578063a1dab23e146107ac578063a8365693146107b45761038e565b80638eab59231461069a5780639137c1a7146106a25780639a508c8e146106c85761038e565b806345d01e4a116102c357806366666aa9116102615780637bb7bed1116102305780637bb7bed11461064757806382de9c1b1461066457806385b97b6f1461066c578063887ee971146106925761038e565b806366666aa91461058e57806366f6e531146105965780636f307dc31461059e5780637484192d146105a65761038e565b8063501859461161029d57806350185946146105505780635641ec0314610576578063596fa9e31461057e5780635aa6e675146105865761038e565b806345d01e4a146105125780634d352ab21461051a5780634fa5d854146105485761038e565b80632e1e04621161033057806337c84e131161030a57806337c84e13146104f25780633e0dc34e146104fa5780633fc8cef314610502578063457100741461050a5761038e565b80632e1e0462146104da5780632ea19326146104e257806336e0004a146104ea5761038e565b80630c80447a1161036c5780630c80447a1461043c5780630dff5c31146104625780631113ef521461049c578063183e9565146104d25761038e565b8063026a0dd01461039357806305191794146103ad57806309ff18f014610418575b600080fd5b61039b610a05565b60408051918252519081900360200190f35b61041660048036036101408110156103c457600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101358216916080820135169060a08101359060c08101359060e0810135151590610100810135906101200135610a36565b005b610420610b46565b604080516001600160a01b039092168252519081900360200190f35b6104166004803603602081101561045257600080fd5b50356001600160a01b0316610b71565b6104886004803603602081101561047857600080fd5b50356001600160a01b0316610c68565b604080519115158252519081900360200190f35b610416600480360360608110156104b257600080fd5b506001600160a01b03813581169160208101359091169060400135610c7d565b610420610e35565b610420610e4d565b61039b610e65565b610420610e6b565b61039b610e96565b61039b610ec1565b610420610eec565b610488610f04565b61039b610f2f565b6104166004803603604081101561053057600080fd5b506001600160a01b038135811691602001351661105d565b6104166112dc565b6104886004803603602081101561056657600080fd5b50356001600160a01b0316611429565b610416611493565b610420611570565b610420611588565b6104206115fb565b61039b611626565b610420611651565b610416600480360360208110156105bc57600080fd5b810190602081018135600160201b8111156105d657600080fd5b8201836020820111156105e857600080fd5b803590602001918460208302840111600160201b8311171561060957600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092955061167c945050505050565b6104206004803603602081101561065d57600080fd5b503561185a565b61039b611881565b6104166004803603602081101561068257600080fd5b50356001600160a01b03166118ac565b6104206119a1565b6104886119cc565b610416600480360360208110156106b857600080fd5b50356001600160a01b03166119f7565b610416611b26565b610416600480360360408110156106e657600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111561071057600080fd5b82018360208201111561072257600080fd5b803590602001918460208302840111600160201b8311171561074357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611c21945050505050565b610789611e45565b6040805192151583526001600160a01b0390911660208301528051918290030190f35b61039b611e91565b61039b611ebc565b610416600480360360208110156107d257600080fd5b50351515611ee7565b61039b611fbb565b610416600480360360208110156107f957600080fd5b5035611fe6565b6104206120ba565b6104166120e5565b61048861225c565b6104166004803603602081101561082e57600080fd5b50356001600160a01b0316612261565b61042061230c565b610420612324565b6104166004803603602081101561086457600080fd5b503561234f565b6104166004803603602081101561088157600080fd5b810190602081018135600160201b81111561089b57600080fd5b8201836020820111156108ad57600080fd5b803590602001918460208302840111600160201b831117156108ce57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506124ca945050505050565b61048861270c565b610416612737565b610416600480360361010081101561093357600080fd5b506001600160a01b03813581169160208101358216916040820135811691606081013582169160808201359160a081013582169160c08201359160e001351661280c565b610420612aa7565b6104206004803603604081101561099557600080fd5b506001600160a01b038135169060200135612ab6565b610416600480360360208110156109c157600080fd5b5035612aeb565b610420600480360360208110156109de57600080fd5b5035612be0565b610420612bed565b610420612c2f565b610420612c5a565b610420612c85565b6000610a307f0286fd414602b432a8c80a0125e9a25de9bba96da9d5068c832ff73f09208a3b612cac565b90505b90565b600054610100900460ff1680610a4f5750610a4f612cb0565b80610a5d575060005460ff16155b610a985760405162461bcd60e51b815260040180806020018281038252602e81526020018061477f602e913960400191505060405180910390fd5b600054610100900460ff16158015610ac3576000805460ff1961ff0019909116610100171660011790555b610acc8b612261565b610ad58a612cb6565b610ade89612ce0565b610ae788612d0a565b610af087612d34565b610af986612d5e565b610b0285612d88565b610b0b84612db2565b610b1483612ddc565b610b1d82612e06565b610b276000612e30565b8015610b39576000805461ff00191690555b5050505050505050505050565b6000610a307f29f7fcd4fe2517c1963807a1ec27b0e45e67c60a874d5eeac7a0b1ab1bb84447612cac565b610b79612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610bce57600080fd5b505afa158015610be2573d6000803e3d6000fd5b505050506040513d6020811015610bf857600080fd5b5051610c3c576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b610c4581612e7f565b610c65610c60610c53611ebc565b429063ffffffff612ea916565b612f0a565b50565b60356020526000908152604090205460ff1681565b610c85612e5a565b6001600160a01b031663b429afeb336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610cda57600080fd5b505afa158015610cee573d6000803e3d6000fd5b505050506040513d6020811015610d0457600080fd5b505180610d965750610d14612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610d6957600080fd5b505afa158015610d7d573d6000803e3d6000fd5b505050506040513d6020811015610d9357600080fd5b50515b610dd15760405162461bcd60e51b815260040180806020018281038252602b81526020018061464e602b913960400191505060405180910390fd5b610dda82611429565b15610e165760405162461bcd60e51b81526004018080602001828103825260228152602001806146796022913960400191505060405180910390fd5b610e306001600160a01b038316848363ffffffff612f3416565b505050565b73f49440c1f012d041802b25a73e5b0b9166a75c0281565b73d9e1ce17f2641f24ae83637ab66a2cca9c378b9f81565b61271081565b6000610a307f3e9de78b54c338efbc04e3a091b87dc7efb5d7024738302c548fc59fba1c34e6612cac565b6000610a307fb7c50ef998211fff3420379d0bf5b8dfb0cee909d1b7d9e517f311c104675b09612cac565b6000610a307f3fd729bfa2e28b7806b03a6e014729f59477b530f995be4d51defc9dad94810b612cac565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6000610a307f656de32df98753b07482576beb0d00a6b949ebf84c066c765f54f26725221bb6612f86565b6000610a30610f3c611651565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610f9157600080fd5b505afa158015610fa5573d6000803e3d6000fd5b505050506040513d6020811015610fbb57600080fd5b5051611051610fc86120ba565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561101d57600080fd5b505afa158015611031573d6000803e3d6000fd5b505050506040513d602081101561104757600080fd5b5051611051612f9a565b9063ffffffff612ea916565b600054610100900460ff16806110765750611076612cb0565b80611084575060005460ff16155b6110bf5760405162461bcd60e51b815260040180806020018281038252602e81526020018061477f602e913960400191505060405180910390fd5b600054610100900460ff161580156110ea576000805460ff1961ff0019909116610100171660011790555b735b5cfe992adac0c9d48e05854b2d91c73a00385873353e489311b21355461353fec2d02b73ef0ede7f73d533a949740bb3306d119cc777fa900ba034cd52734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b736b175474e89094c44da98b954eedeac495271d0f7309672362833d8f703d5395ef3252d4bfa51c15ca61117a89878a88600b8760018861280c565b6040805180820182526001600160a01b03861680825273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2602080840191909152600091825260349052919091206111c69160026145a6565b506040805180820182526001600160a01b03851680825273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2602080840191909152600091825260349052919091206112139160026145a6565b506040805180820190915273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281526001600160a01b03831660208201526112529060339060026145a6565b50604080518082019091526001600160a01b0380861682528416602082015261127f9060369060026145a6565b50506001600160a01b03928316600090815260356020526040808220805460ff1990811690915593851682528082208054851690559190931683529091208054909116905550508015610e30576000805461ff0019169055505050565b6112e461270c565b156113205760405162461bcd60e51b81526004018080602001828103825260348152602001806148316034913960400191505060405180910390fd5b611328612c5a565b6001600160a01b0316336001600160a01b0316148061135f575061134a612bed565b6001600160a01b0316336001600160a01b0316145b80611382575061136d611588565b6001600160a01b0316336001600160a01b0316145b6113bd5760405162461bcd60e51b815260040180806020018281038252603981526020018061469b6039913960400191505060405180910390fd5b6113c56115fb565b6001600160a01b0316633d18b9126040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156113ff57600080fd5b505af1158015611413573d6000803e3d6000fd5b5050505061141f612ff9565b6114276137bb565b565b6000611433612c2f565b6001600160a01b0316826001600160a01b0316148061146a5750611455611651565b6001600160a01b0316826001600160a01b0316145b8061148d57506114786120ba565b6001600160a01b0316826001600160a01b0316145b92915050565b61149b612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156114f057600080fd5b505afa158015611504573d6000803e3d6000fd5b505050506040513d602081101561151a57600080fd5b505161155e576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b611566613898565b6114276001612e30565b737a250d5630b4cf539739df2c5dacb4c659f2488d81565b6000611592612e5a565b6001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b1580156115ca57600080fd5b505afa1580156115de573d6000803e3d6000fd5b505050506040513d60208110156115f457600080fd5b5051905090565b6000610a307f3d9bb16e77837e25cada0cf894835418b38e8e18fbec6cfd192eb344bebfa6b8612cac565b6000610a307fb487e573671f10704ed229d25cf38dda6d287a35872859d096c0395110a0adb1612cac565b6000610a307fa1709211eeccf8f4ad5b6700d52a1a9525b5f5ae1e9e5f9e5a0c2fc23c86e530612cac565b611684612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156116d957600080fd5b505afa1580156116ed573d6000803e3d6000fd5b505050506040513d602081101561170357600080fd5b5051611747576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168160008151811061177257fe5b60200260200101516001600160a01b0316146117d5576040805162461bcd60e51b815260206004820152601b60248201527f506174682073686f756c64207374617274207769746820574554480000000000604482015290519081900360640190fd5b6117dd612324565b6001600160a01b0316816001835103815181106117f657fe5b60200260200101516001600160a01b0316146118435760405162461bcd60e51b81526004018080602001828103825260218152602001806146f86021913960400191505060405180910390fd5b80516118569060339060208401906145a6565b5050565b6036818154811061186757fe5b6000918252602090912001546001600160a01b0316905081565b6000610a307f414c5263b05428f1be1bfa98e25407cc78dd031d0d3cd2a2e3d63b488804f22e612cac565b6118b4612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561190957600080fd5b505afa15801561191d573d6000803e3d6000fd5b505050506040513d602081101561193357600080fd5b5051611977576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b610c657fc26d330f887c749cb38ae7c37873ff08ac4bba7aec9113c82d48a0cf6cc145f282613a1c565b6000610a307fb306bb7adebd5a22f5e4cdf1efa00bc5f62d4f5554ef9d62c1b16327cd3ab5f9612cac565b6000610a307fbc7c0d42a71b75c3129b337a259c346200f901408f273707402da4b51db3b8e7612f86565b6119ff612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611a5457600080fd5b505afa158015611a68573d6000803e3d6000fd5b505050506040513d6020811015611a7e57600080fd5b5051611ac2576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b6001600160a01b038116611b1d576040805162461bcd60e51b815260206004820152601e60248201527f6e65772073746f726167652073686f756c646e277420626520656d7074790000604482015290519081900360640190fd5b610c6581613a20565b611b2e612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611b8357600080fd5b505afa158015611b97573d6000803e3d6000fd5b505050506040513d6020811015611bad57600080fd5b5051611bf1576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b611bf9613a44565b611c1673f49440c1f012d041802b25a73e5b0b9166a75c026118ac565b6114276103e8612aeb565b611c29612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611c7e57600080fd5b505afa158015611c92573d6000803e3d6000fd5b505050506040513d6020811015611ca857600080fd5b5051611cec576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031681600183510381518110611d1a57fe5b60200260200101516001600160a01b031614611d79576040805162461bcd60e51b81526020600482015260196024820152780a0c2e8d040e6d0deead8c840cadcc840eed2e8d040ae8aa89603b1b604482015290519081900360640190fd5b816001600160a01b031681600081518110611d9057fe5b60200260200101516001600160a01b031614611ddd5760405162461bcd60e51b815260040180806020018281038252602281526020018061473c6022913960400191505060405180910390fd5b60368054600181019091557f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b80180546001600160a01b0319166001600160a01b03841690811790915560009081526034602090815260409091208251610e30928401906145a6565b600080611e50611881565b15801590611e645750611e61611881565b42115b8015611e8157506000611e75610b46565b6001600160a01b031614155b611e89610b46565b915091509091565b6000610a307fc403216a7704d160f6a3b5c3b149a1226a6080f0a5dd27b27d9ba9c022fa0afc612cac565b6000610a307f82b330ca72bcd6db11a26f10ce47ebcfe574a9c646bccbc6f1cd4478eae16b31612cac565b611eef612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611f4457600080fd5b505afa158015611f58573d6000803e3d6000fd5b505050506040513d6020811015611f6e57600080fd5b5051611fb2576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b610c6581612db2565b6000610a307fe3ee74fb7893020b457d8071ed1ef76ace2bf4903abd7b24d3ce312e9c72c029612cac565b611fee612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561204357600080fd5b505afa158015612057573d6000803e3d6000fd5b505050506040513d602081101561206d57600080fd5b50516120b1576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b610c6581612ddc565b6000610a307f414478d5ad7f54ead8a3dd018bba4f8d686ba5ab5975cd376e0c98f98fb713c5612cac565b6120ed612c5a565b6001600160a01b0316336001600160a01b03161480612124575061210f612bed565b6001600160a01b0316336001600160a01b0316145b806121475750612132611588565b6001600160a01b0316336001600160a01b0316145b6121825760405162461bcd60e51b815260040180806020018281038252603981526020018061469b6039913960400191505060405180910390fd5b600061218c6115fb565b6001600160a01b0316146121a2576121a2613a58565b6121aa612ff9565b6114276121b5612c5a565b6121bd611651565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561221257600080fd5b505afa158015612226573d6000803e3d6000fd5b505050506040513d602081101561223c57600080fd5b5051612246611651565b6001600160a01b0316919063ffffffff612f3416565b600190565b600054610100900460ff168061227a575061227a612cb0565b80612288575060005460ff16155b6122c35760405162461bcd60e51b815260040180806020018281038252602e81526020018061477f602e913960400191505060405180910390fd5b600054610100900460ff161580156122ee576000805460ff1961ff0019909116610100171660011790555b6122f782613abc565b8015611856576000805461ff00191690555050565b73f403c135812408bfbe8713b5a23a04b3d48aae3181565b6000610a307f219270253dbc530471c88a9e7c321b36afda219583431e7b6c386d2d46e70c86612cac565b612357612c5a565b6001600160a01b0316336001600160a01b0316148061238e5750612379612bed565b6001600160a01b0316336001600160a01b0316145b806123b1575061239c611588565b6001600160a01b0316336001600160a01b0316145b6123ec5760405162461bcd60e51b815260040180806020018281038252603981526020018061469b6039913960400191505060405180910390fd5b60006123f6611651565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561244b57600080fd5b505afa15801561245f573d6000803e3d6000fd5b505050506040513d602081101561247557600080fd5b50519050808211156124b6576000612493838363ffffffff613b5216565b905060006124a86124a2612f9a565b83613b94565b90506124b381613baa565b50505b6118566124c1612c5a565b83612246611651565b6124d2612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561252757600080fd5b505afa15801561253b573d6000803e3d6000fd5b505050506040513d602081101561255157600080fd5b5051612595576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316816001835103815181106125c357fe5b60200260200101516001600160a01b031614612622576040805162461bcd60e51b81526020600482015260196024820152780a0c2e8d040e6d0deead8c840cadcc840eed2e8d040ae8aa89603b1b604482015290519081900360640190fd5b6000805b603654811015612682576036818154811061263d57fe5b600091825260208220015484516001600160a01b0390911691859161265e57fe5b60200260200101516001600160a01b0316141561267a57600191505b600101612626565b50806126bf5760405162461bcd60e51b815260040180806020018281038252602481526020018061480d6024913960400191505060405180910390fd5b8160346000846000815181106126d157fe5b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000209080519060200190610e309291906145a6565b6000610a307fa07a20a2d463a602c2b891eb35f244624d9068572811f63d0e094072fb54591a612f86565b61273f612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561279457600080fd5b505afa1580156127a8573d6000803e3d6000fd5b505050506040513d60208110156127be57600080fd5b5051612802576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b6114276000612e30565b600054610100900460ff16806128255750612825612cb0565b80612833575060005460ff16155b61286e5760405162461bcd60e51b815260040180806020018281038252602e81526020018061477f602e913960400191505060405180910390fd5b600054610100900460ff16158015612899576000805460ff1961ff0019909116610100171660011790555b6128ce8989898973c02aaa39b223fe8d0a0e5c4f27ead9083c756cc261012c6103e86001670de0b6b3a764000061a8c0610a36565b60008073f403c135812408bfbe8713b5a23a04b3d48aae316001600160a01b0316631526fe27886040518263ffffffff1660e01b81526004018082815260200191505060c06040518083038186803b15801561292957600080fd5b505afa15801561293d573d6000803e3d6000fd5b505050506040513d60c081101561295357600080fd5b5080516020909101519092509050612969611651565b6001600160a01b0316826001600160a01b0316146129b85760405162461bcd60e51b81526004018080602001828103825260238152602001806147196023913960400191505060405180910390fd5b600485106129f75760405162461bcd60e51b81526004018080602001828103825260248152602001806146d46024913960400191505060405180910390fd5b612a0085613c04565b612a0987613c2e565b612a1286613c58565b612a1b81613c82565b612a2484613cac565b612a2f6103e8612aeb565b612a4c73f49440c1f012d041802b25a73e5b0b9166a75c026118ac565b6040805160008152602081019182905251612a69916033916145a6565b506040805160008152602081019182905251612a87916036916145a6565b5050508015612a9c576000805461ff00191690555b505050505050505050565b6037546001600160a01b031681565b60346020528160005260406000208181548110612acf57fe5b6000918252602090912001546001600160a01b03169150829050565b612af3612e5a565b6001600160a01b031663dee1f0e4336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015612b4857600080fd5b505afa158015612b5c573d6000803e3d6000fd5b505050506040513d6020811015612b7257600080fd5b5051612bb6576040805162461bcd60e51b815260206004820152600e60248201526d4e6f7420676f7665726e616e636560901b604482015290519081900360640190fd5b610c657fb487e573671f10704ed229d25cf38dda6d287a35872859d096c0395110a0adb182613a1c565b6033818154811061186757fe5b6000612bf7612e5a565b6001600160a01b031663f77c47916040518163ffffffff1660e01b815260040160206040518083038186803b1580156115ca57600080fd5b6000610a307fdae0aafd977983cb1e78d8f638900ff361dc3c48c43118ca1dd77d1af3f47bbf612cac565b6000610a307fefd7c7d9ef1040fc87e7ad11fe15f86e1d11e1df03c6d7c87f7e1f4041f08d41612cac565b6000610a307fc26d330f887c749cb38ae7c37873ff08ac4bba7aec9113c82d48a0cf6cc145f25b5490565b303b1590565b610c657fa1709211eeccf8f4ad5b6700d52a1a9525b5f5ae1e9e5f9e5a0c2fc23c86e53082613a1c565b610c657fefd7c7d9ef1040fc87e7ad11fe15f86e1d11e1df03c6d7c87f7e1f4041f08d4182613a1c565b610c657f3d9bb16e77837e25cada0cf894835418b38e8e18fbec6cfd192eb344bebfa6b882613a1c565b610c657fdae0aafd977983cb1e78d8f638900ff361dc3c48c43118ca1dd77d1af3f47bbf82613a1c565b610c657fe3ee74fb7893020b457d8071ed1ef76ace2bf4903abd7b24d3ce312e9c72c02982613a1c565b610c657f0286fd414602b432a8c80a0125e9a25de9bba96da9d5068c832ff73f09208a3b82613a1c565b610c657f656de32df98753b07482576beb0d00a6b949ebf84c066c765f54f26725221bb682613cd6565b610c657fc403216a7704d160f6a3b5c3b149a1226a6080f0a5dd27b27d9ba9c022fa0afc82613a1c565b610c657f82b330ca72bcd6db11a26f10ce47ebcfe574a9c646bccbc6f1cd4478eae16b3182613a1c565b610c657fa07a20a2d463a602c2b891eb35f244624d9068572811f63d0e094072fb54591a82613cd6565b7fa7ec62784904ff31cbcc32d09932a58e7f1e4476e1d041995b37c917990b16dc5490565b610c657f29f7fcd4fe2517c1963807a1ec27b0e45e67c60a874d5eeac7a0b1ab1bb8444782613a1c565b600082820183811015612f03576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b610c657f414c5263b05428f1be1bfa98e25407cc78dd031d0d3cd2a2e3d63b488804f22e82613a1c565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610e30908490613cf1565b6000612f9182612cac565b60011492915050565b6000612fa46115fb565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156115ca57600080fd5b613001610f04565b61304c577f408a4b113351e616bb41bad991f29bbad84b43c3810e7492a6bc7c6388dfe0c261302e610f04565b604080519115158252600060208301528051918290030190a1611427565b60005b6036548110156133d15760006036828154811061306857fe5b6000918252602080832090910154604080516370a0823160e01b815230600482015290516001600160a01b03909216945084926370a0823192602480840193829003018186803b1580156130bb57600080fd5b505afa1580156130cf573d6000803e3d6000fd5b505050506040513d60208110156130e557600080fd5b5051905080158061310e57506001600160a01b0382166000908152603460205260409020546002115b1561311a5750506133c9565b600061314661271061313a61312d611626565b859063ffffffff613eaf16565b9063ffffffff613f0816565b9050801561318f57613170613159612c85565b6001600160a01b038516908363ffffffff612f3416565b613180828263ffffffff613b5216565b91508161318f575050506133c9565b6001600160a01b03831660009081526035602052604081205460ff16156131cb5750737a250d5630b4cf539739df2c5dacb4c659f2488d6131e2565b5073d9e1ce17f2641f24ae83637ab66a2cca9c378b9f5b6131fd6001600160a01b03851682600063ffffffff613f4a16565b6132176001600160a01b038516828563ffffffff613f4a16565b806001600160a01b03166338ed173984600160346000896001600160a01b03166001600160a01b0316815260200190815260200160002030426040518663ffffffff1660e01b81526004018086815260200185815260200180602001846001600160a01b03166001600160a01b0316815260200183815260200182810382528581815481526020019150805480156132d857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116132ba575b50509650505050505050600060405180830381600087803b1580156132fc57600080fd5b505af1158015613310573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561333957600080fd5b8101908080516040519392919084600160201b82111561335857600080fd5b90830190602082018581111561336d57600080fd5b82518660208202830111600160201b8211171561338957600080fd5b82525081516020918201928201910280838360005b838110156133b657818101518382015260200161339e565b5050505090500160405250505050505050505b60010161304f565b50604080516370a0823160e01b8152306004820152905160009173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2916370a0823191602480820192602092909190829003018186803b15801561342757600080fd5b505afa15801561343b573d6000803e3d6000fd5b505050506040513d602081101561345157600080fd5b5051905061345e8161405d565b6000613468612c2f565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156134bd57600080fd5b505afa1580156134d1573d6000803e3d6000fd5b505050506040513d60208110156134e757600080fd5b50519050806134f7575050611427565b600060356000613505612324565b6001600160a01b0316815260208101919091526040016000205460ff16156135425750737a250d5630b4cf539739df2c5dacb4c659f2488d613559565b5073d9e1ce17f2641f24ae83637ab66a2cca9c378b9f5b61357d816000613567612c2f565b6001600160a01b0316919063ffffffff613f4a16565b61358a8183613567612c2f565b600060019050816001600160a01b03166338ed17398483603330426040518663ffffffff1660e01b81526004018086815260200185815260200180602001846001600160a01b03166001600160a01b03168152602001838152602001828103825285818154815260200191508054801561362d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161360f575b50509650505050505050600060405180830381600087803b15801561365157600080fd5b505af1158015613665573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561368e57600080fd5b8101908080516040519392919084600160201b8211156136ad57600080fd5b9083019060208201858111156136c257600080fd5b82518660208202830111600160201b821117156136de57600080fd5b82525081516020918201928201910280838360005b8381101561370b5781810151838201526020016136f3565b50505050905001604052505050506000613723612324565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561377857600080fd5b505afa15801561378c573d6000803e3d6000fd5b505050506040513d60208110156137a257600080fd5b5051905080156137b4576137b46141b5565b5050505050565b6137c361270c565b156137ff5760405162461bcd60e51b81526004018080602001828103825260348152602001806148316034913960400191505060405180910390fd5b6000613809611651565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561385e57600080fd5b505afa158015613872573d6000803e3d6000fd5b505050506040513d602081101561388857600080fd5b5051111561142757611427614325565b60006138a2612f9a565b90508015613915576138b26115fb565b6001600160a01b0316631c1c6fe560006040518263ffffffff1660e01b81526004018082151515158152602001915050600060405180830381600087803b1580156138fc57600080fd5b505af1158015613910573d6000803e3d6000fd5b505050505b600061391f6120ba565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561397457600080fd5b505afa158015613988573d6000803e3d6000fd5b505050506040513d602081101561399e57600080fd5b5051905080156118565773f403c135812408bfbe8713b5a23a04b3d48aae3163958e2d316139ca610ec1565b6040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015613a0057600080fd5b505af1158015613a14573d6000803e3d6000fd5b505050505050565b9055565b7fa7ec62784904ff31cbcc32d09932a58e7f1e4476e1d041995b37c917990b16dc55565b613a4e6000612e7f565b6114276000612f0a565b6000613a62612f9a565b9050801561391557613a726115fb565b6001600160a01b0316631c1c6fe560016040518263ffffffff1660e01b81526004018082151515158152602001915050600060405180830381600087803b1580156138fc57600080fd5b600054610100900460ff1680613ad55750613ad5612cb0565b80613ae3575060005460ff16155b613b1e5760405162461bcd60e51b815260040180806020018281038252602e81526020018061477f602e913960400191505060405180910390fd5b600054610100900460ff16158015613b49576000805460ff1961ff0019909116610100171660011790555b6122f782613a20565b6000612f0383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061446e565b6000818310613ba35781612f03565b5090919050565b613bb26115fb565b6001600160a01b03166338d074368260006040518363ffffffff1660e01b8152600401808381526020018215151515815260200192505050600060405180830381600087803b1580156138fc57600080fd5b610c657fb7c50ef998211fff3420379d0bf5b8dfb0cee909d1b7d9e517f311c104675b0982613a1c565b610c657f3fd729bfa2e28b7806b03a6e014729f59477b530f995be4d51defc9dad94810b82613a1c565b610c657f219270253dbc530471c88a9e7c321b36afda219583431e7b6c386d2d46e70c8682613a1c565b610c657f414478d5ad7f54ead8a3dd018bba4f8d686ba5ab5975cd376e0c98f98fb713c582613a1c565b610c657fb306bb7adebd5a22f5e4cdf1efa00bc5f62d4f5554ef9d62c1b16327cd3ab5f982613a1c565b6118568282613ce6576000613ce9565b60015b60ff16613a1c565b613d03826001600160a01b0316614505565b613d54576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310613d925780518252601f199092019160209182019101613d73565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613df4576040519150601f19603f3d011682016040523d82523d6000602084013e613df9565b606091505b509150915081613e50576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115613ea957808060200190516020811015613e6c57600080fd5b5051613ea95760405162461bcd60e51b815260040180806020018281038252602a8152602001806147ad602a913960400191505060405180910390fd5b50505050565b600082613ebe5750600061148d565b82820282848281613ecb57fe5b0414612f035760405162461bcd60e51b815260040180806020018281038252602181526020018061475e6021913960400191505060405180910390fd5b6000612f0383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614541565b801580613fd0575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b158015613fa257600080fd5b505afa158015613fb6573d6000803e3d6000fd5b505050506040513d6020811015613fcc57600080fd5b5051155b61400b5760405162461bcd60e51b81526004018080602001828103825260368152602001806147d76036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610e30908490613cf1565b801561417357600061407b614070610a05565b61313a61312d611fbb565b6040805184815260208101839052428183015290519192507f33fd2845a0f10293482de360244dd4ad31ddbb4b8c4a1ded3875cf8ebfba184b919081900360600190a16140d36140c9612bed565b6000613567612c2f565b6140e76140de612bed565b82613567612c2f565b6140ef612bed565b6001600160a01b031663f706bf28614105612c2f565b836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561415557600080fd5b505af1158015614169573d6000803e3d6000fd5b5050505050610c65565b6040805160008082526020820152428183015290517f33fd2845a0f10293482de360244dd4ad31ddbb4b8c4a1ded3875cf8ebfba184b9181900360600190a150565b60006141bf612324565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561421457600080fd5b505afa158015614228573d6000803e3d6000fd5b505050506040513d602081101561423e57600080fd5b5051905061425761424d6119a1565b6000613567612324565b61426b6142626119a1565b82613567612324565b61427361460b565b818161427d610e96565b6004811061428757fe5b602002015260006142966119a1565b6001600160a01b031663029b2f3483836040518363ffffffff1660e01b81526004018083600460200280838360005b838110156142dd5781810151838201526020016142c5565b5050505090500182815260200192505050600060405180830381600087803b15801561430857600080fd5b505af115801561431c573d6000803e3d6000fd5b50505050505050565b600061432f611651565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561438457600080fd5b505afa158015614398573d6000803e3d6000fd5b505050506040513d60208110156143ae57600080fd5b505190506143d473f403c135812408bfbe8713b5a23a04b3d48aae316000613567611651565b6143f573f403c135812408bfbe8713b5a23a04b3d48aae3182613567611651565b73f403c135812408bfbe8713b5a23a04b3d48aae316360759fce614417610ec1565b60016040518363ffffffff1660e01b8152600401808381526020018215151515815260200192505050600060405180830381600087803b15801561445a57600080fd5b505af11580156137b4573d6000803e3d6000fd5b600081848411156144fd5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156144c25781810151838201526020016144aa565b50505050905090810190601f1680156144ef5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061453957508115155b949350505050565b600081836145905760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156144c25781810151838201526020016144aa565b50600083858161459c57fe5b0495945050505050565b8280548282559060005260206000209081019282156145fb579160200282015b828111156145fb57825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906145c6565b50614607929150614629565b5090565b60405180608001604052806004906020820280388339509192915050565b610a3391905b808211156146075780546001600160a01b031916815560010161462f56fe5468652063616c6c6572206d75737420626520636f6e74726f6c6c6572206f7220676f7665726e616e6365746f6b656e20697320646566696e6564206173206e6f742073616c76616761626c655468652073656e6465722068617320746f2062652074686520636f6e74726f6c6c65722c20676f7665726e616e63652c206f72207661756c744465706f73697420617272617920706f736974696f6e206f7574206f6620626f756e6473506174682073686f756c6420656e642077697468206465706f736974546f6b656e506f6f6c20496e666f20646f6573206e6f74206d6174636820756e6465726c79696e67506174682073686f756c64207374617274207769746820726577617264546f6b656e536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a65645361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365506174682073686f756c642073746172742077697468206120726577617264546f6b656e416374696f6e20626c6f636b65642061732074686520737472617465677920697320696e20656d657267656e6379207374617465a265627a7a72315820238985b22045a94951a92753734aa6858ca279011ea88d38e8d3b92781e3239164736f6c63430005100032