ETH Price: $3,333.41 (-0.30%)

Contract

0xc4a59cfEd3FE06bDB5C21dE75A70B20dB280D8fE
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Whitelist LP...125998282021-06-09 10:30:231297 days ago1623234623IN
0xc4a59cfE...dB280D8fE
0 ETH0.0019101210.2
Set Whitelist LP...125525472021-06-02 3:17:581304 days ago1622603878IN
0xc4a59cfE...dB280D8fE
0 ETH0.0073758924
Set Whitelist LP...125159462021-05-27 10:47:401310 days ago1622112460IN
0xc4a59cfE...dB280D8fE
0 ETH0.0213928527.00000145
Set Whitelist LP...123279992021-04-28 9:05:241339 days ago1619600724IN
0xc4a59cfE...dB280D8fE
0 ETH0.0328125936.00000134

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
133060932021-09-27 5:52:561187 days ago1632721976
0xc4a59cfE...dB280D8fE
2 wei
133060932021-09-27 5:52:561187 days ago1632721976
0xc4a59cfE...dB280D8fE
2 wei
133060932021-09-27 5:52:561187 days ago1632721976
0xc4a59cfE...dB280D8fE
2.2 ETH
133060932021-09-27 5:52:561187 days ago1632721976
0xc4a59cfE...dB280D8fE
2.2 ETH
133059592021-09-27 5:22:301187 days ago1632720150
0xc4a59cfE...dB280D8fE
0 ETH
133059592021-09-27 5:22:301187 days ago1632720150
0xc4a59cfE...dB280D8fE
0 ETH
133059592021-09-27 5:22:301187 days ago1632720150
0xc4a59cfE...dB280D8fE
1,290 ETH
133059592021-09-27 5:22:301187 days ago1632720150
0xc4a59cfE...dB280D8fE
1,290 ETH
133059482021-09-27 5:20:581187 days ago1632720058
0xc4a59cfE...dB280D8fE
1,290 ETH
133059482021-09-27 5:20:581187 days ago1632720058
0xc4a59cfE...dB280D8fE
1,290 ETH
133059172021-09-27 5:13:071187 days ago1632719587
0xc4a59cfE...dB280D8fE
1,036.60735104 ETH
133059172021-09-27 5:13:071187 days ago1632719587
0xc4a59cfE...dB280D8fE
1,036.60735104 ETH
133059172021-09-27 5:13:071187 days ago1632719587
0xc4a59cfE...dB280D8fE
1,042.78106025 ETH
133059172021-09-27 5:13:071187 days ago1632719587
0xc4a59cfE...dB280D8fE
1,042.78106025 ETH
133009592021-09-26 10:50:271188 days ago1632653427
0xc4a59cfE...dB280D8fE
1.66779928 ETH
133009592021-09-26 10:50:271188 days ago1632653427
0xc4a59cfE...dB280D8fE
1.66779928 ETH
132994832021-09-26 5:12:141188 days ago1632633134
0xc4a59cfE...dB280D8fE
1,290 ETH
132994832021-09-26 5:12:141188 days ago1632633134
0xc4a59cfE...dB280D8fE
1,290 ETH
132994662021-09-26 5:08:571188 days ago1632632937
0xc4a59cfE...dB280D8fE
1,290 ETH
132994662021-09-26 5:08:571188 days ago1632632937
0xc4a59cfE...dB280D8fE
1,290 ETH
132994292021-09-26 4:59:291188 days ago1632632369
0xc4a59cfE...dB280D8fE
1,357.86340618 ETH
132994292021-09-26 4:59:291188 days ago1632632369
0xc4a59cfE...dB280D8fE
1,357.86340618 ETH
132994292021-09-26 4:59:291188 days ago1632632369
0xc4a59cfE...dB280D8fE
1,358.01263782 ETH
132994292021-09-26 4:59:291188 days ago1632632369
0xc4a59cfE...dB280D8fE
1,358.01263782 ETH
132993952021-09-26 4:50:111188 days ago1632631811
0xc4a59cfE...dB280D8fE
0.33029261 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SushiswapSpellV1

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2021-04-28
*/

// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;



// Part: IBank

interface IBank {
  /// The governor adds a new bank gets added to the system.
  event AddBank(address token, address cToken);
  /// The governor sets the address of the oracle smart contract.
  event SetOracle(address oracle);
  /// The governor sets the basis point fee of the bank.
  event SetFeeBps(uint feeBps);
  /// The governor withdraw tokens from the reserve of a bank.
  event WithdrawReserve(address user, address token, uint amount);
  /// Someone borrows tokens from a bank via a spell caller.
  event Borrow(uint positionId, address caller, address token, uint amount, uint share);
  /// Someone repays tokens to a bank via a spell caller.
  event Repay(uint positionId, address caller, address token, uint amount, uint share);
  /// Someone puts tokens as collateral via a spell caller.
  event PutCollateral(uint positionId, address caller, address token, uint id, uint amount);
  /// Someone takes tokens from collateral via a spell caller.
  event TakeCollateral(uint positionId, address caller, address token, uint id, uint amount);
  /// Someone calls liquidatation on a position, paying debt and taking collateral tokens.
  event Liquidate(
    uint positionId,
    address liquidator,
    address debtToken,
    uint amount,
    uint share,
    uint bounty
  );

  /// @dev Return the current position while under execution.
  function POSITION_ID() external view returns (uint);

  /// @dev Return the current target while under execution.
  function SPELL() external view returns (address);

  /// @dev Return the current executor (the owner of the current position).
  function EXECUTOR() external view returns (address);

  /// @dev Return bank information for the given token.
  function getBankInfo(address token)
    external
    view
    returns (
      bool isListed,
      address cToken,
      uint reserve,
      uint totalDebt,
      uint totalShare
    );

  /// @dev Return position information for the given position id.
  function getPositionInfo(uint positionId)
    external
    view
    returns (
      address owner,
      address collToken,
      uint collId,
      uint collateralSize
    );

  /// @dev Return the borrow balance for given positon and token without trigger interest accrual.
  function borrowBalanceStored(uint positionId, address token) external view returns (uint);

  /// @dev Trigger interest accrual and return the current borrow balance.
  function borrowBalanceCurrent(uint positionId, address token) external returns (uint);

  /// @dev Borrow tokens from the bank.
  function borrow(address token, uint amount) external;

  /// @dev Repays tokens to the bank.
  function repay(address token, uint amountCall) external;

  /// @dev Transmit user assets to the spell.
  function transmit(address token, uint amount) external;

  /// @dev Put more collateral for users.
  function putCollateral(
    address collToken,
    uint collId,
    uint amountCall
  ) external;

  /// @dev Take some collateral back.
  function takeCollateral(
    address collToken,
    uint collId,
    uint amount
  ) external;

  /// @dev Liquidate a position.
  function liquidate(
    uint positionId,
    address debtToken,
    uint amountCall
  ) external;

  function getBorrowETHValue(uint positionId) external view returns (uint);

  function accrue(address token) external;

  function nextPositionId() external view returns (uint);

  /// @dev Return current position information.
  function getCurrentPositionInfo()
    external
    view
    returns (
      address owner,
      address collToken,
      uint collId,
      uint collateralSize
    );

  function support(address token) external view returns (bool);

}

// Part: IERC20Wrapper

interface IERC20Wrapper {
  /// @dev Return the underlying ERC-20 for the given ERC-1155 token id.
  function getUnderlyingToken(uint id) external view returns (address);

  /// @dev Return the conversion rate from ERC-1155 to ERC-20, multiplied by 2**112.
  function getUnderlyingRate(uint id) external view returns (uint);
}

// Part: IMasterChef

interface IMasterChef {
  function sushi() external view returns (address);

  function poolInfo(uint pid)
    external
    view
    returns (
      address lpToken,
      uint allocPoint,
      uint lastRewardBlock,
      uint accSushiPerShare
    );

  function deposit(uint pid, uint amount) external;

  function withdraw(uint pid, uint amount) external;
}

// Part: IUniswapV2Factory

// https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/interfaces/IUniswapV2Factory.sol

interface IUniswapV2Factory {
  event PairCreated(address indexed token0, address indexed token1, address pair, uint);

  function feeTo() external view returns (address);

  function feeToSetter() external view returns (address);

  function getPair(address tokenA, address tokenB) external view returns (address pair);

  function allPairs(uint) external view returns (address pair);

  function allPairsLength() external view returns (uint);

  function createPair(address tokenA, address tokenB) external returns (address pair);

  function setFeeTo(address) external;

  function setFeeToSetter(address) external;
}

// Part: IUniswapV2Pair

// https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/interfaces/IUniswapV2Pair.sol

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;
}

// Part: IUniswapV2Router01

// https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/interfaces/IUniswapV2Router01.sol

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);
}

// Part: IUniswapV2Router02

interface IUniswapV2Router02 is IUniswapV2Router01 {
  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;
}

// Part: IWETH

interface IWETH {
  function balanceOf(address user) external returns (uint);

  function approve(address to, uint value) external returns (bool);

  function transfer(address to, uint value) external returns (bool);

  function deposit() external payable;

  function withdraw(uint) external;
}

// Part: OpenZeppelin/[email protected]/Address

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

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

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// Part: OpenZeppelin/[email protected]/IERC165

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// Part: OpenZeppelin/[email protected]/IERC20

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

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

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

// Part: OpenZeppelin/[email protected]/SafeMath

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, 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 (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @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) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @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) {
        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, reverting 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) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting 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) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

// Part: HomoraMath

library HomoraMath {
  using SafeMath for uint;

  function divCeil(uint lhs, uint rhs) internal pure returns (uint) {
    return lhs.add(rhs).sub(1) / rhs;
  }

  function fmul(uint lhs, uint rhs) internal pure returns (uint) {
    return lhs.mul(rhs) / (2**112);
  }

  function fdiv(uint lhs, uint rhs) internal pure returns (uint) {
    return lhs.mul(2**112) / rhs;
  }

  // implementation from https://github.com/Uniswap/uniswap-lib/commit/99f3f28770640ba1bb1ff460ac7c5292fb8291a0
  // original implementation: https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.sol#L687
  function sqrt(uint x) internal pure returns (uint) {
    if (x == 0) return 0;
    uint xx = x;
    uint r = 1;

    if (xx >= 0x100000000000000000000000000000000) {
      xx >>= 128;
      r <<= 64;
    }

    if (xx >= 0x10000000000000000) {
      xx >>= 64;
      r <<= 32;
    }
    if (xx >= 0x100000000) {
      xx >>= 32;
      r <<= 16;
    }
    if (xx >= 0x10000) {
      xx >>= 16;
      r <<= 8;
    }
    if (xx >= 0x100) {
      xx >>= 8;
      r <<= 4;
    }
    if (xx >= 0x10) {
      xx >>= 4;
      r <<= 2;
    }
    if (xx >= 0x8) {
      r <<= 1;
    }

    r = (r + x / r) >> 1;
    r = (r + x / r) >> 1;
    r = (r + x / r) >> 1;
    r = (r + x / r) >> 1;
    r = (r + x / r) >> 1;
    r = (r + x / r) >> 1;
    r = (r + x / r) >> 1; // Seven iterations should be enough
    uint r1 = x / r;
    return (r < r1 ? r : r1);
  }
}

// Part: OpenZeppelin/[email protected]/ERC165

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts may inherit from this and call {_registerInterface} to declare
 * their support of an interface.
 */
abstract contract ERC165 is IERC165 {
    /*
     * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
     */
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

    /**
     * @dev Mapping of interface ids to whether or not it's supported.
     */
    mapping(bytes4 => bool) private _supportedInterfaces;

    constructor () internal {
        // Derived contracts need only register support for their own interfaces,
        // we register support for ERC165 itself here
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     *
     * Time complexity O(1), guaranteed to always use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    /**
     * @dev Registers the contract as an implementer of the interface defined by
     * `interfaceId`. Support of the actual ERC165 interface is automatic and
     * registering its interface id is not required.
     *
     * See {IERC165-supportsInterface}.
     *
     * Requirements:
     *
     * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
     */
    function _registerInterface(bytes4 interfaceId) internal virtual {
        require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
        _supportedInterfaces[interfaceId] = true;
    }
}

// Part: OpenZeppelin/[email protected]/IERC1155

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values);

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external;
}

// Part: OpenZeppelin/[email protected]/IERC1155Receiver

/**
 * _Available since v3.1._
 */
interface IERC1155Receiver is IERC165 {

    /**
        @dev Handles the receipt of a single ERC1155 token type. This function is
        called at the end of a `safeTransferFrom` after the balance has been updated.
        To accept the transfer, this must return
        `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
        (i.e. 0xf23a6e61, or its own function selector).
        @param operator The address which initiated the transfer (i.e. msg.sender)
        @param from The address which previously owned the token
        @param id The ID of the token being transferred
        @param value The amount of tokens being transferred
        @param data Additional data with no specified format
        @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
    */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    )
        external
        returns(bytes4);

    /**
        @dev Handles the receipt of a multiple ERC1155 token types. This function
        is called at the end of a `safeBatchTransferFrom` after the balances have
        been updated. To accept the transfer(s), this must return
        `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
        (i.e. 0xbc197c81, or its own function selector).
        @param operator The address which initiated the batch transfer (i.e. msg.sender)
        @param from The address which previously owned the token
        @param ids An array containing ids of each token being transferred (order and length must match values array)
        @param values An array containing amounts of each token being transferred (order and length must match ids array)
        @param data Additional data with no specified format
        @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
    */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    )
        external
        returns(bytes4);
}

// Part: OpenZeppelin/[email protected]/Initializable

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 */
abstract 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 protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already 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) {
        return !Address.isContract(address(this));
    }
}

// Part: OpenZeppelin/[email protected]/SafeERC20

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

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

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

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

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

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

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// Part: Governable

contract Governable is Initializable {
  event SetGovernor(address governor);
  event SetPendingGovernor(address pendingGovernor);
  event AcceptGovernor(address governor);

  address public governor; // The current governor.
  address public pendingGovernor; // The address pending to become the governor once accepted.

  bytes32[64] _gap; // reserve space for upgrade

  modifier onlyGov() {
    require(msg.sender == governor, 'not the governor');
    _;
  }

  /// @dev Initialize using msg.sender as the first governor.
  function __Governable__init() internal initializer {
    governor = msg.sender;
    pendingGovernor = address(0);
    emit SetGovernor(msg.sender);
  }

  /// @dev Set the pending governor, which will be the governor once accepted.
  /// @param _pendingGovernor The address to become the pending governor.
  function setPendingGovernor(address _pendingGovernor) external onlyGov {
    pendingGovernor = _pendingGovernor;
    emit SetPendingGovernor(_pendingGovernor);
  }

  /// @dev Accept to become the new governor. Must be called by the pending governor.
  function acceptGovernor() external {
    require(msg.sender == pendingGovernor, 'not the pending governor');
    pendingGovernor = address(0);
    governor = msg.sender;
    emit AcceptGovernor(msg.sender);
  }
}

// Part: IWERC20

interface IWERC20 is IERC1155, IERC20Wrapper {
  /// @dev Return the underlying ERC20 balance for the user.
  function balanceOfERC20(address token, address user) external view returns (uint);

  /// @dev Mint ERC1155 token for the given ERC20 token.
  function mint(address token, uint amount) external;

  /// @dev Burn ERC1155 token to redeem ERC20 token back.
  function burn(address token, uint amount) external;
}

// Part: IWMasterChef

interface IWMasterChef is IERC1155, IERC20Wrapper {
  /// @dev Mint ERC1155 token for the given ERC20 token.
  function mint(uint pid, uint amount) external returns (uint id);

  /// @dev Burn ERC1155 token to redeem ERC20 token back.
  function burn(uint id, uint amount) external returns (uint pid);

  function sushi() external returns (IERC20);

  function decodeId(uint id) external pure returns (uint, uint);

  function chef() external view returns (IMasterChef);
}

// Part: OpenZeppelin/[email protected]/ERC1155Receiver

/**
 * @dev _Available since v3.1._
 */
abstract contract ERC1155Receiver is ERC165, IERC1155Receiver {
    constructor() internal {
        _registerInterface(
            ERC1155Receiver(address(0)).onERC1155Received.selector ^
            ERC1155Receiver(address(0)).onERC1155BatchReceived.selector
        );
    }
}

// Part: ERC1155NaiveReceiver

contract ERC1155NaiveReceiver is ERC1155Receiver {
  bytes32[64] __gap; // reserve space for upgrade

  function onERC1155Received(
    address, /* operator */
    address, /* from */
    uint, /* id */
    uint, /* value */
    bytes calldata /* data */
  ) external override returns (bytes4) {
    return this.onERC1155Received.selector;
  }

  function onERC1155BatchReceived(
    address, /* operator */
    address, /* from */
    uint[] calldata, /* ids */
    uint[] calldata, /* values */
    bytes calldata /* data */
  ) external override returns (bytes4) {
    return this.onERC1155BatchReceived.selector;
  }
}

// Part: BasicSpell

abstract contract BasicSpell is ERC1155NaiveReceiver {
  using SafeERC20 for IERC20;

  IBank public immutable bank;
  IWERC20 public immutable werc20;
  address public immutable weth;

  mapping(address => mapping(address => bool)) public approved; // Mapping from token to (mapping from spender to approve status)

  constructor(
    IBank _bank,
    address _werc20,
    address _weth
  ) public {
    bank = _bank;
    werc20 = IWERC20(_werc20);
    weth = _weth;
    ensureApprove(_weth, address(_bank));
    IWERC20(_werc20).setApprovalForAll(address(_bank), true);
  }

  /// @dev Ensure that the spell has approved the given spender to spend all of its tokens.
  /// @param token The token to approve.
  /// @param spender The spender to allow spending.
  /// NOTE: This is safe because spell is never built to hold fund custody.
  function ensureApprove(address token, address spender) internal {
    if (!approved[token][spender]) {
      IERC20(token).safeApprove(spender, uint(-1));
      approved[token][spender] = true;
    }
  }

  /// @dev Internal call to convert msg.value ETH to WETH inside the contract.
  function doTransmitETH() internal {
    if (msg.value > 0) {
      IWETH(weth).deposit{value: msg.value}();
    }
  }

  /// @dev Internal call to transmit tokens from the bank if amount is positive.
  /// @param token The token to perform the transmit action.
  /// @param amount The amount to transmit.
  /// @notice Do not use `amount` input argument to handle the received amount.
  function doTransmit(address token, uint amount) internal {
    if (amount > 0) {
      bank.transmit(token, amount);
    }
  }

  /// @dev Internal call to refund tokens to the current bank executor.
  /// @param token The token to perform the refund action.
  function doRefund(address token) internal {
    uint balance = IERC20(token).balanceOf(address(this));
    if (balance > 0) {
      IERC20(token).safeTransfer(bank.EXECUTOR(), balance);
    }
  }

  /// @dev Internal call to refund all WETH to the current executor as native ETH.
  function doRefundETH() internal {
    uint balance = IWETH(weth).balanceOf(address(this));
    if (balance > 0) {
      IWETH(weth).withdraw(balance);
      (bool success, ) = bank.EXECUTOR().call{value: balance}(new bytes(0));
      require(success, 'refund ETH failed');
    }
  }

  /// @dev Internal call to borrow tokens from the bank on behalf of the current executor.
  /// @param token The token to borrow from the bank.
  /// @param amount The amount to borrow.
  /// @notice Do not use `amount` input argument to handle the received amount.
  function doBorrow(address token, uint amount) internal {
    if (amount > 0) {
      bank.borrow(token, amount);
    }
  }

  /// @dev Internal call to repay tokens to the bank on behalf of the current executor.
  /// @param token The token to repay to the bank.
  /// @param amount The amount to repay.
  function doRepay(address token, uint amount) internal {
    if (amount > 0) {
      ensureApprove(token, address(bank));
      bank.repay(token, amount);
    }
  }

  /// @dev Internal call to put collateral tokens in the bank.
  /// @param token The token to put in the bank.
  /// @param amount The amount to put in the bank.
  function doPutCollateral(address token, uint amount) internal {
    if (amount > 0) {
      ensureApprove(token, address(werc20));
      werc20.mint(token, amount);
      bank.putCollateral(address(werc20), uint(token), amount);
    }
  }

  /// @dev Internal call to take collateral tokens from the bank.
  /// @param token The token to take back.
  /// @param amount The amount to take back.
  function doTakeCollateral(address token, uint amount) internal {
    if (amount > 0) {
      if (amount == uint(-1)) {
        (, , , amount) = bank.getCurrentPositionInfo();
      }
      bank.takeCollateral(address(werc20), uint(token), amount);
      werc20.burn(token, amount);
    }
  }

  /// @dev Fallback function. Can only receive ETH from WETH contract.
  receive() external payable {
    require(msg.sender == weth, 'ETH must come from WETH');
  }
}

// Part: WhitelistSpell

contract WhitelistSpell is BasicSpell, Governable {
  mapping(address => bool) public whitelistedLpTokens; // mapping from lp token to whitelist status

  constructor(
    IBank _bank,
    address _werc20,
    address _weth
  ) public BasicSpell(_bank, _werc20, _weth) {
    __Governable__init();
  }

  /// @dev Set whitelist LP token statuses for spell
  /// @param lpTokens LP tokens to set whitelist statuses
  /// @param statuses Whitelist statuses
  function setWhitelistLPTokens(address[] calldata lpTokens, bool[] calldata statuses)
    external
    onlyGov
  {
    require(lpTokens.length == statuses.length, 'lpTokens & statuses length mismatched');
    for (uint idx = 0; idx < lpTokens.length; idx++) {
      if (statuses[idx]) {
        require(bank.support(lpTokens[idx]), 'oracle not support lp token');
      }
      whitelistedLpTokens[lpTokens[idx]] = statuses[idx];
    }
  }
}

// File: SushiswapSpellV1.sol

contract SushiswapSpellV1 is WhitelistSpell {
  using SafeMath for uint;
  using HomoraMath for uint;

  IUniswapV2Factory public immutable factory; // Sushiswap factory
  IUniswapV2Router02 public immutable router; // Sushiswap router

  mapping(address => mapping(address => address)) public pairs; // Mapping from tokenA to (mapping from tokenB to LP token)

  IWMasterChef public immutable wmasterchef; // Wrapped masterChef

  address public immutable sushi; // Sushi token address

  constructor(
    IBank _bank,
    address _werc20,
    IUniswapV2Router02 _router,
    address _wmasterchef
  ) public WhitelistSpell(_bank, _werc20, _router.WETH()) {
    router = _router;
    factory = IUniswapV2Factory(_router.factory());
    wmasterchef = IWMasterChef(_wmasterchef);
    IWMasterChef(_wmasterchef).setApprovalForAll(address(_bank), true);
    sushi = address(IWMasterChef(_wmasterchef).sushi());
  }

  /// @dev Return the LP token for the token pairs (can be in any order)
  /// @param tokenA Token A to get LP token
  /// @param tokenB Token B to get LP token
  function getAndApprovePair(address tokenA, address tokenB) public returns (address) {
    address lp = pairs[tokenA][tokenB];
    if (lp == address(0)) {
      lp = factory.getPair(tokenA, tokenB);
      require(lp != address(0), 'no lp token');
      ensureApprove(tokenA, address(router));
      ensureApprove(tokenB, address(router));
      ensureApprove(lp, address(router));
      pairs[tokenA][tokenB] = lp;
      pairs[tokenB][tokenA] = lp;
    }
    return lp;
  }

  /// @dev Compute optimal deposit amount
  /// @param amtA amount of token A desired to deposit
  /// @param amtB amount of token B desired to deposit
  /// @param resA amount of token A in reserve
  /// @param resB amount of token B in reserve
  function optimalDeposit(
    uint amtA,
    uint amtB,
    uint resA,
    uint resB
  ) internal pure returns (uint swapAmt, bool isReversed) {
    if (amtA.mul(resB) >= amtB.mul(resA)) {
      swapAmt = _optimalDepositA(amtA, amtB, resA, resB);
      isReversed = false;
    } else {
      swapAmt = _optimalDepositA(amtB, amtA, resB, resA);
      isReversed = true;
    }
  }

  /// @dev Compute optimal deposit amount helper.
  /// @param amtA amount of token A desired to deposit
  /// @param amtB amount of token B desired to deposit
  /// @param resA amount of token A in reserve
  /// @param resB amount of token B in reserve
  /// Formula: https://blog.alphafinance.io/byot/
  function _optimalDepositA(
    uint amtA,
    uint amtB,
    uint resA,
    uint resB
  ) internal pure returns (uint) {
    require(amtA.mul(resB) >= amtB.mul(resA), 'Reversed');
    uint a = 997;
    uint b = uint(1997).mul(resA);
    uint _c = (amtA.mul(resB)).sub(amtB.mul(resA));
    uint c = _c.mul(1000).div(amtB.add(resB)).mul(resA);
    uint d = a.mul(c).mul(4);
    uint e = HomoraMath.sqrt(b.mul(b).add(d));
    uint numerator = e.sub(b);
    uint denominator = a.mul(2);
    return numerator.div(denominator);
  }

  struct Amounts {
    uint amtAUser; // Supplied tokenA amount
    uint amtBUser; // Supplied tokenB amount
    uint amtLPUser; // Supplied LP token amount
    uint amtABorrow; // Borrow tokenA amount
    uint amtBBorrow; // Borrow tokenB amount
    uint amtLPBorrow; // Borrow LP token amount
    uint amtAMin; // Desired tokenA amount (slippage control)
    uint amtBMin; // Desired tokenB amount (slippage control)
  }

  /// @dev Add liquidity to Sushiswap pool
  /// @param tokenA Token A for the pair
  /// @param tokenB Token B for the pair
  /// @param amt Amounts of tokens to supply, borrow, and get.
  function addLiquidityInternal(
    address tokenA,
    address tokenB,
    Amounts calldata amt,
    address lp
  ) internal {
    require(whitelistedLpTokens[lp], 'lp token not whitelisted');

    // 1. Get user input amounts
    doTransmitETH();
    doTransmit(tokenA, amt.amtAUser);
    doTransmit(tokenB, amt.amtBUser);
    doTransmit(lp, amt.amtLPUser);

    // 2. Borrow specified amounts
    doBorrow(tokenA, amt.amtABorrow);
    doBorrow(tokenB, amt.amtBBorrow);
    doBorrow(lp, amt.amtLPBorrow);

    // 3. Calculate optimal swap amount
    uint swapAmt;
    bool isReversed;
    {
      uint amtA = IERC20(tokenA).balanceOf(address(this));
      uint amtB = IERC20(tokenB).balanceOf(address(this));
      uint resA;
      uint resB;
      if (IUniswapV2Pair(lp).token0() == tokenA) {
        (resA, resB, ) = IUniswapV2Pair(lp).getReserves();
      } else {
        (resB, resA, ) = IUniswapV2Pair(lp).getReserves();
      }
      (swapAmt, isReversed) = optimalDeposit(amtA, amtB, resA, resB);
    }

    // 4. Swap optimal amount
    if (swapAmt > 0) {
      address[] memory path = new address[](2);
      (path[0], path[1]) = isReversed ? (tokenB, tokenA) : (tokenA, tokenB);
      router.swapExactTokensForTokens(swapAmt, 0, path, address(this), block.timestamp);
    }

    // 5. Add liquidity
    uint balA = IERC20(tokenA).balanceOf(address(this));
    uint balB = IERC20(tokenB).balanceOf(address(this));
    if (balA > 0 || balB > 0) {
      router.addLiquidity(
        tokenA,
        tokenB,
        balA,
        balB,
        amt.amtAMin,
        amt.amtBMin,
        address(this),
        block.timestamp
      );
    }
  }

  /// @dev Add liquidity to Sushiswap pool, with no staking rewards (use WERC20 wrapper)
  /// @param tokenA Token A for the pair
  /// @param tokenB Token B for the pair
  /// @param amt Amounts of tokens to supply, borrow, and get.
  function addLiquidityWERC20(
    address tokenA,
    address tokenB,
    Amounts calldata amt
  ) external payable {
    address lp = getAndApprovePair(tokenA, tokenB);
    // 1-5. add liquidity
    addLiquidityInternal(tokenA, tokenB, amt, lp);

    // 6. Put collateral
    doPutCollateral(lp, IERC20(lp).balanceOf(address(this)));

    // 7. Refund leftovers to users
    doRefundETH();
    doRefund(tokenA);
    doRefund(tokenB);
  }

  /// @dev Add liquidity to Sushiswap pool, with staking to masterChef
  /// @param tokenA Token A for the pair
  /// @param tokenB Token B for the pair
  /// @param amt Amounts of tokens to supply, borrow, and get.
  /// @param pid Pool id
  function addLiquidityWMasterChef(
    address tokenA,
    address tokenB,
    Amounts calldata amt,
    uint pid
  ) external payable {
    address lp = getAndApprovePair(tokenA, tokenB);
    (address lpToken, , , ) = wmasterchef.chef().poolInfo(pid);
    require(lpToken == lp, 'incorrect lp token');

    // 1-5. add liquidity
    addLiquidityInternal(tokenA, tokenB, amt, lp);

    // 6. Take out collateral
    (, address collToken, uint collId, uint collSize) = bank.getCurrentPositionInfo();
    if (collSize > 0) {
      (uint decodedPid, ) = wmasterchef.decodeId(collId);
      require(pid == decodedPid, 'incorrect pid');
      require(collToken == address(wmasterchef), 'collateral token & wmasterchef mismatched');
      bank.takeCollateral(address(wmasterchef), collId, collSize);
      wmasterchef.burn(collId, collSize);
    }

    // 7. Put collateral
    ensureApprove(lp, address(wmasterchef));
    uint amount = IERC20(lp).balanceOf(address(this));
    uint id = wmasterchef.mint(pid, amount);
    bank.putCollateral(address(wmasterchef), id, amount);

    // 8. Refund leftovers to users
    doRefundETH();
    doRefund(tokenA);
    doRefund(tokenB);

    // 9. Refund sushi
    doRefund(sushi);
  }

  struct RepayAmounts {
    uint amtLPTake; // Take out LP token amount (from Homora)
    uint amtLPWithdraw; // Withdraw LP token amount (back to caller)
    uint amtARepay; // Repay tokenA amount
    uint amtBRepay; // Repay tokenB amount
    uint amtLPRepay; // Repay LP token amount
    uint amtAMin; // Desired tokenA amount
    uint amtBMin; // Desired tokenB amount
  }

  /// @dev Remove liquidity from Sushiswap pool
  /// @param tokenA Token A for the pair
  /// @param tokenB Token B for the pair
  /// @param amt Amounts of tokens to take out, withdraw, repay, and get.
  function removeLiquidityInternal(
    address tokenA,
    address tokenB,
    RepayAmounts calldata amt,
    address lp
  ) internal {
    require(whitelistedLpTokens[lp], 'lp token not whitelisted');
    uint positionId = bank.POSITION_ID();

    uint amtARepay = amt.amtARepay;
    uint amtBRepay = amt.amtBRepay;
    uint amtLPRepay = amt.amtLPRepay;

    // 2. Compute repay amount if MAX_INT is supplied (max debt)
    if (amtARepay == uint(-1)) {
      amtARepay = bank.borrowBalanceCurrent(positionId, tokenA);
    }
    if (amtBRepay == uint(-1)) {
      amtBRepay = bank.borrowBalanceCurrent(positionId, tokenB);
    }
    if (amtLPRepay == uint(-1)) {
      amtLPRepay = bank.borrowBalanceCurrent(positionId, lp);
    }

    // 3. Compute amount to actually remove
    uint amtLPToRemove = IERC20(lp).balanceOf(address(this)).sub(amt.amtLPWithdraw);

    // 4. Remove liquidity
    uint amtA;
    uint amtB;
    if (amtLPToRemove > 0) {
      (amtA, amtB) = router.removeLiquidity(
        tokenA,
        tokenB,
        amtLPToRemove,
        0,
        0,
        address(this),
        block.timestamp
      );
    }

    // 5. MinimizeTrading
    uint amtADesired = amtARepay.add(amt.amtAMin);
    uint amtBDesired = amtBRepay.add(amt.amtBMin);

    if (amtA < amtADesired && amtB > amtBDesired) {
      address[] memory path = new address[](2);
      (path[0], path[1]) = (tokenB, tokenA);
      router.swapTokensForExactTokens(
        amtADesired.sub(amtA),
        amtB.sub(amtBDesired),
        path,
        address(this),
        block.timestamp
      );
    } else if (amtA > amtADesired && amtB < amtBDesired) {
      address[] memory path = new address[](2);
      (path[0], path[1]) = (tokenA, tokenB);
      router.swapTokensForExactTokens(
        amtBDesired.sub(amtB),
        amtA.sub(amtADesired),
        path,
        address(this),
        block.timestamp
      );
    }

    // 6. Repay
    doRepay(tokenA, amtARepay);
    doRepay(tokenB, amtBRepay);
    doRepay(lp, amtLPRepay);

    // 7. Slippage control
    require(IERC20(tokenA).balanceOf(address(this)) >= amt.amtAMin);
    require(IERC20(tokenB).balanceOf(address(this)) >= amt.amtBMin);
    require(IERC20(lp).balanceOf(address(this)) >= amt.amtLPWithdraw);

    // 8. Refund leftover
    doRefundETH();
    doRefund(tokenA);
    doRefund(tokenB);
    doRefund(lp);
  }

  /// @dev Remove liquidity from Sushiswap pool, with no staking rewards (use WERC20 wrapper)
  /// @param tokenA Token A for the pair
  /// @param tokenB Token B for the pair
  /// @param amt Amounts of tokens to take out, withdraw, repay, and get.
  function removeLiquidityWERC20(
    address tokenA,
    address tokenB,
    RepayAmounts calldata amt
  ) external {
    address lp = getAndApprovePair(tokenA, tokenB);

    // 1. Take out collateral
    doTakeCollateral(lp, amt.amtLPTake);

    // 2-8. remove liquidity
    removeLiquidityInternal(tokenA, tokenB, amt, lp);
  }

  /// @dev Remove liquidity from Sushiswap pool, from masterChef staking
  /// @param tokenA Token A for the pair
  /// @param tokenB Token B for the pair
  /// @param amt Amounts of tokens to take out, withdraw, repay, and get.
  function removeLiquidityWMasterChef(
    address tokenA,
    address tokenB,
    RepayAmounts calldata amt
  ) external {
    address lp = getAndApprovePair(tokenA, tokenB);
    (, address collToken, uint collId, ) = bank.getCurrentPositionInfo();
    require(IWMasterChef(collToken).getUnderlyingToken(collId) == lp, 'incorrect underlying');
    require(collToken == address(wmasterchef), 'collateral token & wmasterchef mismatched');

    // 1. Take out collateral
    bank.takeCollateral(address(wmasterchef), collId, amt.amtLPTake);
    wmasterchef.burn(collId, amt.amtLPTake);

    // 2-8. remove liquidity
    removeLiquidityInternal(tokenA, tokenB, amt, lp);

    // 9. Refund sushi
    doRefund(sushi);
  }

  /// @dev Harvest SUSHI reward tokens to in-exec position's owner
  function harvestWMasterChef() external {
    (, address collToken, uint collId, ) = bank.getCurrentPositionInfo();
    (uint pid, ) = wmasterchef.decodeId(collId);
    address lp = wmasterchef.getUnderlyingToken(collId);
    require(whitelistedLpTokens[lp], 'lp token not whitelisted');
    require(collToken == address(wmasterchef), 'collateral token & wmasterchef mismatched');

    // 1. Take out collateral
    bank.takeCollateral(address(wmasterchef), collId, uint(-1));
    wmasterchef.burn(collId, uint(-1));

    // 2. put collateral
    uint amount = IERC20(lp).balanceOf(address(this));
    ensureApprove(lp, address(wmasterchef));
    uint id = wmasterchef.mint(pid, amount);
    bank.putCollateral(address(wmasterchef), id, amount);

    // 3. Refund sushi
    doRefund(sushi);
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IBank","name":"_bank","type":"address"},{"internalType":"address","name":"_werc20","type":"address"},{"internalType":"contract IUniswapV2Router02","name":"_router","type":"address"},{"internalType":"address","name":"_wmasterchef","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"governor","type":"address"}],"name":"AcceptGovernor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"governor","type":"address"}],"name":"SetGovernor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pendingGovernor","type":"address"}],"name":"SetPendingGovernor","type":"event"},{"inputs":[],"name":"acceptGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"components":[{"internalType":"uint256","name":"amtAUser","type":"uint256"},{"internalType":"uint256","name":"amtBUser","type":"uint256"},{"internalType":"uint256","name":"amtLPUser","type":"uint256"},{"internalType":"uint256","name":"amtABorrow","type":"uint256"},{"internalType":"uint256","name":"amtBBorrow","type":"uint256"},{"internalType":"uint256","name":"amtLPBorrow","type":"uint256"},{"internalType":"uint256","name":"amtAMin","type":"uint256"},{"internalType":"uint256","name":"amtBMin","type":"uint256"}],"internalType":"struct SushiswapSpellV1.Amounts","name":"amt","type":"tuple"}],"name":"addLiquidityWERC20","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"components":[{"internalType":"uint256","name":"amtAUser","type":"uint256"},{"internalType":"uint256","name":"amtBUser","type":"uint256"},{"internalType":"uint256","name":"amtLPUser","type":"uint256"},{"internalType":"uint256","name":"amtABorrow","type":"uint256"},{"internalType":"uint256","name":"amtBBorrow","type":"uint256"},{"internalType":"uint256","name":"amtLPBorrow","type":"uint256"},{"internalType":"uint256","name":"amtAMin","type":"uint256"},{"internalType":"uint256","name":"amtBMin","type":"uint256"}],"internalType":"struct SushiswapSpellV1.Amounts","name":"amt","type":"tuple"},{"internalType":"uint256","name":"pid","type":"uint256"}],"name":"addLiquidityWMasterChef","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"approved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bank","outputs":[{"internalType":"contract IBank","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract IUniswapV2Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"getAndApprovePair","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvestWMasterChef","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"pairs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingGovernor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"components":[{"internalType":"uint256","name":"amtLPTake","type":"uint256"},{"internalType":"uint256","name":"amtLPWithdraw","type":"uint256"},{"internalType":"uint256","name":"amtARepay","type":"uint256"},{"internalType":"uint256","name":"amtBRepay","type":"uint256"},{"internalType":"uint256","name":"amtLPRepay","type":"uint256"},{"internalType":"uint256","name":"amtAMin","type":"uint256"},{"internalType":"uint256","name":"amtBMin","type":"uint256"}],"internalType":"struct SushiswapSpellV1.RepayAmounts","name":"amt","type":"tuple"}],"name":"removeLiquidityWERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"components":[{"internalType":"uint256","name":"amtLPTake","type":"uint256"},{"internalType":"uint256","name":"amtLPWithdraw","type":"uint256"},{"internalType":"uint256","name":"amtARepay","type":"uint256"},{"internalType":"uint256","name":"amtBRepay","type":"uint256"},{"internalType":"uint256","name":"amtLPRepay","type":"uint256"},{"internalType":"uint256","name":"amtAMin","type":"uint256"},{"internalType":"uint256","name":"amtBMin","type":"uint256"}],"internalType":"struct SushiswapSpellV1.RepayAmounts","name":"amt","type":"tuple"}],"name":"removeLiquidityWMasterChef","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pendingGovernor","type":"address"}],"name":"setPendingGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"lpTokens","type":"address[]"},{"internalType":"bool[]","name":"statuses","type":"bool[]"}],"name":"setWhitelistLPTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sushi","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"werc20","outputs":[{"internalType":"contract IWERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelistedLpTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wmasterchef","outputs":[{"internalType":"contract IWMasterChef","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

6101606040523480156200001257600080fd5b50604051620052c1380380620052c1833981016040819052620000359162000832565b8383836001600160a01b031663ad5c46486040518163ffffffff1660e01b815260040160206040518083038186803b1580156200007157600080fd5b505afa15801562000086573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000ac9190620007f1565b828282620000c16301ffc9a760e01b62000323565b620000d3630271189760e51b62000323565b6001600160601b0319606084811b821660805283811b821660a05282901b1660c0526200010181846200037e565b60405163a22cb46560e01b81526001600160a01b0383169063a22cb4659062000132908690600190600401620008fe565b600060405180830381600087803b1580156200014d57600080fd5b505af115801562000162573d6000803e3d6000fd5b50505050505050620001796200040860201b60201c565b505050816001600160a01b0316610100816001600160a01b031660601b81525050816001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b158015620001d457600080fd5b505afa158015620001e9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200020f9190620007f1565b6001600160601b0319606091821b811660e0529082901b166101205260405163a22cb46560e01b81526001600160a01b0382169063a22cb465906200025c908790600190600401620008fe565b600060405180830381600087803b1580156200027757600080fd5b505af11580156200028c573d6000803e3d6000fd5b50505050806001600160a01b0316630a0879036040518163ffffffff1660e01b8152600401602060405180830381600087803b158015620002cc57600080fd5b505af1158015620002e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003079190620007f1565b60601b6001600160601b031916610140525062000b5992505050565b6001600160e01b03198082161415620003595760405162461bcd60e51b8152600401620003509062000967565b60405180910390fd5b6001600160e01b0319166000908152602081905260409020805460ff19166001179055565b6001600160a01b0380831660009081526041602090815260408083209385168352929052205460ff166200040457620003d381600019846001600160a01b0316620004fa60201b62001b34179092919060201c565b6001600160a01b038083166000908152604160209081526040808320938516835292905220805460ff191660011790555b5050565b604254610100900460ff16806200042457506200042462000608565b8062000433575060425460ff16155b620004525760405162461bcd60e51b81526004016200035090620009e4565b604254610100900460ff161580156200047e576042805460ff1961ff0019909116610100171660011790555b6042805462010000600160b01b0319163362010000810291909117909155604380546001600160a01b03191690556040517fbce074c8369e26e70e1ae2f14fc944da352cfe6f52e2de9572f0c9942a24b7fc91620004dc91620008d0565b60405180910390a18015620004f7576042805461ff00191690555b50565b801580620005895750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90620005339030908690600401620008e4565b60206040518083038186803b1580156200054c57600080fd5b505afa15801562000561573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000587919062000899565b155b620005a85760405162461bcd60e51b8152600401620003509062000ab3565b620006038363095ea7b360e01b8484604051602401620005ca92919062000919565b60408051808303601f190181529190526020810180516001600160e01b0319939093166001600160e01b03938416179052906200062616565b505050565b60006200062030620006c260201b62001c331760201c565b15905090565b606062000682826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316620006c860201b62001c39179092919060201c565b805190915015620006035780806020019051810190620006a3919062000810565b620006035760405162461bcd60e51b8152600401620003509062000a69565b3b151590565b6060620006d98484600085620006e3565b90505b9392505050565b606082471015620007085760405162461bcd60e51b815260040162000350906200099e565b6200071385620006c2565b620007325760405162461bcd60e51b8152600401620003509062000a32565b60006060866001600160a01b03168587604051620007519190620008b2565b60006040518083038185875af1925050503d806000811462000790576040519150601f19603f3d011682016040523d82523d6000602084013e62000795565b606091505b509092509050620007a8828286620007b3565b979650505050505050565b60608315620007c4575081620006dc565b825115620007d55782518084602001fd5b8160405162461bcd60e51b815260040162000350919062000932565b60006020828403121562000803578081fd5b8151620006dc8162000b43565b60006020828403121562000822578081fd5b81518015158114620006dc578182fd5b6000806000806080858703121562000848578283fd5b8451620008558162000b43565b6020860151909450620008688162000b43565b60408601519093506200087b8162000b43565b60608601519092506200088e8162000b43565b939692955090935050565b600060208284031215620008ab578081fd5b5051919050565b60008251620008c681846020870162000b10565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b03929092168252602082015260400190565b60006020825282518060208401526200095381604085016020870162000b10565b601f01601f19169190910160400192915050565b6020808252601c908201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000606082015260800190565b60005b8381101562000b2d57818101518382015260200162000b13565b8381111562000b3d576000848401525b50505050565b6001600160a01b0381168114620004f757600080fd5b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6145c962000cf86000398061046e5280610c67528061103552806117b3525080610762528061080252806108d9528061096c52806109e15280610af65280610b345280610c045280610d185280610e905280610f235280610f97528061115c5280611366528061140e52806114a1528061151452806115a8528061165152806117365250806105cb52806105f5528061061f5280611b1252806121ae52806122df528061240c5280612c1e5280612de2525080610516528061106f52508061015f52806106a25280612fc5528061306b5280613436525080610caa5280611d3e5280611db25280612e955280612ed05280612f7e5250806106c9528061093f5280610bd75280610cf45280610d4d5280610ef652806112af5280611474528061170952806119055280611c645280611d105280611e595280611f1a5280611fc7528061207452806127bb5280612f4e52806130d6528061339d52806133d852806134c2528061351652506145c96000f3fe60806040526004361061014f5760003560e01c806395723b1c116100b6578063e58bb6391161006f578063e58bb6391461039f578063ee42c6f4146103b4578063f235757f146103d4578063f23a6e61146103f4578063f4b1604514610414578063f887ea4014610434576101a7565b806395723b1c14610302578063bc197c8114610322578063c45a01551461034f578063cc9b188014610364578063e07d904e14610377578063e3056a341461038a576101a7565b806340a65ad21161010857806340a65ad21461026e5780634bab09f6146102835780635741229c146102a357806369454b86146102b857806376cdb03b146102d857806386adcc79146102ed576101a7565b806301ffc9a7146101ac5780630a087903146101e25780630c340a24146102045780631387d96d146102195780632185059f146102395780633fc8cef314610259576101a7565b366101a757336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101a55760405162461bcd60e51b815260040161019c9061426f565b60405180910390fd5b005b600080fd5b3480156101b857600080fd5b506101cc6101c7366004613d6d565b610449565b6040516101d99190613fa1565b60405180910390f35b3480156101ee57600080fd5b506101f761046c565b6040516101d99190613eb0565b34801561021057600080fd5b506101f7610490565b34801561022557600080fd5b506101a5610234366004613ae6565b6104a5565b34801561024557600080fd5b506101f761025436600461395a565b6104d0565b34801561026557600080fd5b506101f76106a0565b34801561027a57600080fd5b506101a56106c4565b34801561028f57600080fd5b506101cc61029e366004613922565b610c93565b3480156102af57600080fd5b506101f7610ca8565b3480156102c457600080fd5b506101f76102d336600461395a565b610ccc565b3480156102e457600080fd5b506101f7610cf2565b3480156102f957600080fd5b506101f7610d16565b34801561030e57600080fd5b506101a561031d366004613ae6565b610d3a565b34801561032e57600080fd5b5061034261033d366004613992565b611059565b6040516101d99190613fac565b34801561035b57600080fd5b506101f761106d565b6101a5610372366004613a4d565b611091565b6101a5610385366004613a95565b61114a565b34801561039657600080fd5b506101f76117e4565b3480156103ab57600080fd5b506101a56117f3565b3480156103c057600080fd5b506101a56103cf366004613c37565b611883565b3480156103e057600080fd5b506101a56103ef366004613922565b611a58565b34801561040057600080fd5b5061034261040f366004613b7f565b611ade565b34801561042057600080fd5b506101cc61042f36600461395a565b611af0565b34801561044057600080fd5b506101f7611b10565b6001600160e01b0319811660009081526020819052604090205460ff165b919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6042546201000090046001600160a01b031681565b60006104b184846104d0565b90506104be818335611c52565b6104ca84848484611e1d565b50505050565b6001600160a01b0380831660009081526085602090815260408083208585168452909152812054909116806106975760405163e6a4390560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e6a439059061054d9087908790600401613ec4565b60206040518083038186803b15801561056557600080fd5b505afa158015610579573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059d919061393e565b90506001600160a01b0381166105c55760405162461bcd60e51b815260040161019c906141e7565b6105ef847f00000000000000000000000000000000000000000000000000000000000000006126b8565b610619837f00000000000000000000000000000000000000000000000000000000000000006126b8565b610643817f00000000000000000000000000000000000000000000000000000000000000006126b8565b6001600160a01b0380851660008181526085602081815260408084208987168552825280842080549688166001600160a01b0319978816811790915592825280842094845293905291902080549092161790555b90505b92915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b15801561072057600080fd5b505afa158015610734573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107589190613b38565b50925092505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dc20c6fa836040518263ffffffff1660e01b81526004016107ac919061447e565b604080518083038186803b1580156107c357600080fd5b505afa1580156107d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fb9190613e01565b50905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a4775772846040518263ffffffff1660e01b815260040161084c919061447e565b60206040518083038186803b15801561086457600080fd5b505afa158015610878573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089c919061393e565b6001600160a01b03811660009081526084602052604090205490915060ff166108d75760405162461bcd60e51b815260040161019c90614238565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b0316146109285760405162461bcd60e51b815260040161019c906142e7565b604051630d1d697560e31b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906368eb4ba89061099a907f000000000000000000000000000000000000000000000000000000000000000090879060001990600401613f80565b600060405180830381600087803b1580156109b457600080fd5b505af11580156109c8573d6000803e3d6000fd5b505060405163b390c0ab60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063b390c0ab9150610a1c908690600019906004016144da565b602060405180830381600087803b158015610a3657600080fd5b505af1158015610a4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6e9190613de9565b506040516370a0823160e01b81526000906001600160a01b038316906370a0823190610a9e903090600401613eb0565b60206040518083038186803b158015610ab657600080fd5b505afa158015610aca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aee9190613de9565b9050610b1a827f00000000000000000000000000000000000000000000000000000000000000006126b8565b604051630d9778e560e11b81526000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690631b2ef1ca90610b6b90879086906004016144da565b602060405180830381600087803b158015610b8557600080fd5b505af1158015610b99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbd9190613de9565b60405163314568d960e01b81529091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063314568d990610c30907f00000000000000000000000000000000000000000000000000000000000000009085908790600401613f80565b600060405180830381600087803b158015610c4a57600080fd5b505af1158015610c5e573d6000803e3d6000fd5b50505050610c8b7f000000000000000000000000000000000000000000000000000000000000000061272f565b505050505050565b60846020526000908152604090205460ff1681565b7f000000000000000000000000000000000000000000000000000000000000000081565b60856020908152600092835260408084209091529082529020546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610d4684846104d0565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b158015610da457600080fd5b505afa158015610db8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ddc9190613b38565b509250925050826001600160a01b0316826001600160a01b031663a4775772836040518263ffffffff1660e01b8152600401610e18919061447e565b60206040518083038186803b158015610e3057600080fd5b505afa158015610e44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e68919061393e565b6001600160a01b031614610e8e5760405162461bcd60e51b815260040161019c906143b0565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614610edf5760405162461bcd60e51b815260040161019c906142e7565b604051630d1d697560e31b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906368eb4ba890610f50907f0000000000000000000000000000000000000000000000000000000000000000908590893590600401613f80565b600060405180830381600087803b158015610f6a57600080fd5b505af1158015610f7e573d6000803e3d6000fd5b505060405163b390c0ab60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063b390c0ab9150610fd19084908835906004016144da565b602060405180830381600087803b158015610feb57600080fd5b505af1158015610fff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110239190613de9565b5061103086868686611e1d565b610c8b7f000000000000000000000000000000000000000000000000000000000000000061272f565b63bc197c8160e01b98975050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600061109d84846104d0565b90506110ab8484848461285b565b61113081826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016110db9190613eb0565b60206040518083038186803b1580156110f357600080fd5b505afa158015611107573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112b9190613de9565b612e89565b611138612fab565b6111418461272f565b6104ca8361272f565b600061115685856104d0565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631fc8bc5d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156111b357600080fd5b505afa1580156111c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111eb919061393e565b6001600160a01b0316631526fe27846040518263ffffffff1660e01b8152600401611216919061447e565b60806040518083038186803b15801561122e57600080fd5b505afa158015611242573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112669190613bf9565b5050509050816001600160a01b0316816001600160a01b03161461129c5760405162461bcd60e51b815260040161019c9061420c565b6112a88686868561285b565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b15801561130657600080fd5b505afa15801561131a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133e9190613b38565b919550935091505080156115a257604051636e10637d60e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063dc20c6fa9061139b90869060040161447e565b604080518083038186803b1580156113b257600080fd5b505afa1580156113c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ea9190613e01565b50905080871461140c5760405162461bcd60e51b815260040161019c90614352565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b03161461145d5760405162461bcd60e51b815260040161019c906142e7565b604051630d1d697560e31b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906368eb4ba8906114cd907f00000000000000000000000000000000000000000000000000000000000000009087908790600401613f80565b600060405180830381600087803b1580156114e757600080fd5b505af11580156114fb573d6000803e3d6000fd5b505060405163b390c0ab60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063b390c0ab915061154d90869086906004016144da565b602060405180830381600087803b15801561156757600080fd5b505af115801561157b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159f9190613de9565b50505b6115cc857f00000000000000000000000000000000000000000000000000000000000000006126b8565b6040516370a0823160e01b81526000906001600160a01b038716906370a08231906115fb903090600401613eb0565b60206040518083038186803b15801561161357600080fd5b505afa158015611627573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061164b9190613de9565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631b2ef1ca89846040518363ffffffff1660e01b815260040161169d9291906144da565b602060405180830381600087803b1580156116b757600080fd5b505af11580156116cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ef9190613de9565b60405163314568d960e01b81529091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063314568d990611762907f00000000000000000000000000000000000000000000000000000000000000009085908790600401613f80565b600060405180830381600087803b15801561177c57600080fd5b505af1158015611790573d6000803e3d6000fd5b5050505061179c612fab565b6117a58b61272f565b6117ae8a61272f565b6117d77f000000000000000000000000000000000000000000000000000000000000000061272f565b5050505050505050505050565b6043546001600160a01b031681565b6043546001600160a01b0316331461181d5760405162461bcd60e51b815260040161019c9061401f565b604380546001600160a01b03191690556042805462010000600160b01b03191633620100008102919091179091556040517fd345d81ce68c70b119a17eee79dc1421700bd9cb21ca148a62dc90983964e82f9161187991613eb0565b60405180910390a1565b6042546201000090046001600160a01b031633146118b35760405162461bcd60e51b815260040161019c90614178565b8281146118d25760405162461bcd60e51b815260040161019c906141a2565b60005b83811015611a51578282828181106118e957fe5b90506020020160208101906118fe9190613d35565b156119db577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e660cc0886868481811061193e57fe5b90506020020160208101906119539190613922565b6040518263ffffffff1660e01b815260040161196f9190613eb0565b60206040518083038186803b15801561198757600080fd5b505afa15801561199b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119bf9190613d51565b6119db5760405162461bcd60e51b815260040161019c9061408d565b8282828181106119e757fe5b90506020020160208101906119fc9190613d35565b60846000878785818110611a0c57fe5b9050602002016020810190611a219190613922565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790556001016118d5565b5050505050565b6042546201000090046001600160a01b03163314611a885760405162461bcd60e51b815260040161019c90614178565b604380546001600160a01b0319166001600160a01b0383161790556040517f964dea888b00b2ab53f13dfe7ca334b46e99338c222ae232d98547a1da019f6090611ad3908390613eb0565b60405180910390a150565b63f23a6e6160e01b9695505050505050565b604160209081526000928352604080842090915290825290205460ff1681565b7f000000000000000000000000000000000000000000000000000000000000000081565b801580611bbc5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90611b6a9030908690600401613ec4565b60206040518083038186803b158015611b8257600080fd5b505afa158015611b96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bba9190613de9565b155b611bd85760405162461bcd60e51b815260040161019c90614428565b611c2e8363095ea7b360e01b8484604051602401611bf7929190613f67565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526131f4565b505050565b3b151590565b6060611c488484600085613283565b90505b9392505050565b8015611e1957600019811415611cf9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b158015611cbb57600080fd5b505afa158015611ccf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf39190613b38565b93505050505b604051630d1d697560e31b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116916368eb4ba891611d6b917f0000000000000000000000000000000000000000000000000000000000000000918716908690600401613f80565b600060405180830381600087803b158015611d8557600080fd5b505af1158015611d99573d6000803e3d6000fd5b5050604051632770a7eb60e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169250639dc29fac9150611deb9085908590600401613f67565b600060405180830381600087803b158015611e0557600080fd5b505af1158015610c8b573d6000803e3d6000fd5b5050565b6001600160a01b03811660009081526084602052604090205460ff16611e555760405162461bcd60e51b815260040161019c90614238565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d7ac71ff6040518163ffffffff1660e01b815260040160206040518083038186803b158015611eb057600080fd5b505afa158015611ec4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee89190613de9565b9050604083013560608401356080850135600019831415611fa6576040516320a8bee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906382a2fb9c90611f519087908c90600401614487565b602060405180830381600087803b158015611f6b57600080fd5b505af1158015611f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa39190613de9565b92505b600019821415612053576040516320a8bee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906382a2fb9c90611ffe9087908b90600401614487565b602060405180830381600087803b15801561201857600080fd5b505af115801561202c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120509190613de9565b91505b600019811415612100576040516320a8bee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906382a2fb9c906120ab9087908990600401614487565b602060405180830381600087803b1580156120c557600080fd5b505af11580156120d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fd9190613de9565b90505b600061218c8760200135876001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016121369190613eb0565b60206040518083038186803b15801561214e57600080fd5b505afa158015612162573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121869190613de9565b90613344565b9050600080821561224757604051635d5155ef60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063baa2abde906121f0908e908e908890600090819030904290600401613ede565b6040805180830381600087803b15801561220957600080fd5b505af115801561221d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122419190613e01565b90925090505b60006122578760a08c013561336c565b905060006122698760c08d013561336c565b9050818410801561227957508083115b156123985760408051600280825260608083018452926020830190803683370190505090508c8e826000815181106122ad57fe5b60200260200101836001815181106122c157fe5b6001600160a01b0393841660209182029290920101529181169091527f000000000000000000000000000000000000000000000000000000000000000016638803dbee61230e8588613344565b6123188786613344565b8430426040518663ffffffff1660e01b815260040161233b95949392919061449e565b600060405180830381600087803b15801561235557600080fd5b505af1158015612369573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526123919190810190613ca0565b50506124c1565b81841180156123a657508083105b156124c15760408051600280825260608083018452926020830190803683370190505090508d8d826000815181106123da57fe5b60200260200101836001815181106123ee57fe5b6001600160a01b0393841660209182029290920101529181169091527f000000000000000000000000000000000000000000000000000000000000000016638803dbee61243b8487613344565b6124458887613344565b8430426040518663ffffffff1660e01b815260040161246895949392919061449e565b600060405180830381600087803b15801561248257600080fd5b505af1158015612496573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526124be9190810190613ca0565b50505b6124cb8d89613391565b6124d58c88613391565b6124df8a87613391565b6040516370a0823160e01b815260a08c0135906001600160a01b038f16906370a0823190612511903090600401613eb0565b60206040518083038186803b15801561252957600080fd5b505afa15801561253d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125619190613de9565b101561256c57600080fd5b6040516370a0823160e01b815260c08c0135906001600160a01b038e16906370a082319061259e903090600401613eb0565b60206040518083038186803b1580156125b657600080fd5b505afa1580156125ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ee9190613de9565b10156125f957600080fd5b6040516370a0823160e01b815260208c0135906001600160a01b038c16906370a082319061262b903090600401613eb0565b60206040518083038186803b15801561264357600080fd5b505afa158015612657573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061267b9190613de9565b101561268657600080fd5b61268e612fab565b6126978d61272f565b6126a08c61272f565b6126a98a61272f565b50505050505050505050505050565b6001600160a01b0380831660009081526041602090815260408083209385168352929052205460ff16611e19576126fb6001600160a01b03831682600019611b34565b6001600160a01b038083166000908152604160209081526040808320938516835292905220805460ff191660011790555050565b6040516370a0823160e01b81526000906001600160a01b038316906370a082319061275e903090600401613eb0565b60206040518083038186803b15801561277657600080fd5b505afa15801561278a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ae9190613de9565b90508015611e1957611e197f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663630dc7cb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561281257600080fd5b505afa158015612826573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284a919061393e565b6001600160a01b038416908361340f565b6001600160a01b03811660009081526084602052604090205460ff166128935760405162461bcd60e51b815260040161019c90614238565b61289b61342e565b6128a68483356134a5565b6128b48383602001356134a5565b6128c28183604001356134a5565b6128d08483606001356134f9565b6128de8383608001356134f9565b6128ec818360a001356134f9565b6000806000866001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161291d9190613eb0565b60206040518083038186803b15801561293557600080fd5b505afa158015612949573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296d9190613de9565b90506000866001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161299d9190613eb0565b60206040518083038186803b1580156129b557600080fd5b505afa1580156129c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ed9190613de9565b9050600080896001600160a01b0316876001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b158015612a3557600080fd5b505afa158015612a49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6d919061393e565b6001600160a01b03161415612b0357866001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015612ab557600080fd5b505afa158015612ac9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aed9190613d95565b506001600160701b039182169350169050612b86565b866001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015612b3c57600080fd5b505afa158015612b50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b749190613d95565b506001600160701b0390811693501690505b612b928484848461354d565b90965094505084159250612cb791505057604080516002808252606080830184529260208301908036833701905050905081612bcf578686612bd2565b85875b82600081518110612bdf57fe5b6020026020010183600181518110612bf357fe5b6001600160a01b0393841660209182029290920101529181169091526040516338ed173960e01b81527f0000000000000000000000000000000000000000000000000000000000000000909116906338ed173990612c5e90869060009086903090429060040161449e565b600060405180830381600087803b158015612c7857600080fd5b505af1158015612c8c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612cb49190810190613ca0565b50505b6040516370a0823160e01b81526000906001600160a01b038816906370a0823190612ce6903090600401613eb0565b60206040518083038186803b158015612cfe57600080fd5b505afa158015612d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d369190613de9565b90506000866001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612d669190613eb0565b60206040518083038186803b158015612d7e57600080fd5b505afa158015612d92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612db69190613de9565b90506000821180612dc75750600081115b15612e7f5760405162e8e33760e81b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e8e3370090612e2d908b908b908790879060c08e01359060e08f01359030904290600401613f1e565b606060405180830381600087803b158015612e4757600080fd5b505af1158015612e5b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d79190613e24565b5050505050505050565b8015611e1957612eb9827f00000000000000000000000000000000000000000000000000000000000000006126b8565b6040516340c10f1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990612f079085908590600401613f67565b600060405180830381600087803b158015612f2157600080fd5b505af1158015612f35573d6000803e3d6000fd5b505060405163314568d960e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116935063314568d99250611deb917f0000000000000000000000000000000000000000000000000000000000000000918716908690600401613f80565b6040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190612ffa903090600401613eb0565b602060405180830381600087803b15801561301457600080fd5b505af1158015613028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304c9190613de9565b905080156131f157604051632e1a7d4d60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632e1a7d4d906130a090849060040161447e565b600060405180830381600087803b1580156130ba57600080fd5b505af11580156130ce573d6000803e3d6000fd5b5050505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663630dc7cb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561312d57600080fd5b505afa158015613141573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613165919061393e565b604080516000815260208101918290526001600160a01b039290921691849161318e9190613e94565b60006040518083038185875af1925050503d80600081146131cb576040519150601f19603f3d011682016040523d82523d6000602084013e6131d0565b606091505b5050905080611e195760405162461bcd60e51b815260040161019c90613ff4565b50565b6060613249826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611c399092919063ffffffff16565b805190915015611c2e57808060200190518101906132679190613d51565b611c2e5760405162461bcd60e51b815260040161019c906143de565b6060824710156132a55760405162461bcd60e51b815260040161019c906140fb565b6132ae85611c33565b6132ca5760405162461bcd60e51b815260040161019c90614379565b60006060866001600160a01b031685876040516132e79190613e94565b60006040518083038185875af1925050503d8060008114613324576040519150601f19603f3d011682016040523d82523d6000602084013e613329565b606091505b509150915061333982828661359c565b979650505050505050565b6000828211156133665760405162461bcd60e51b815260040161019c906140c4565b50900390565b6000828201838110156106975760405162461bcd60e51b815260040161019c90614056565b8015611e19576133c1827f00000000000000000000000000000000000000000000000000000000000000006126b8565b604051630450cfaf60e31b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906322867d7890611deb9085908590600401613f67565b611c2e8363a9059cbb60e01b8484604051602401611bf7929190613f67565b34156134a3577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561348f57600080fd5b505af1158015611a51573d6000803e3d6000fd5b565b8015611e195760405163246b5de160e11b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906348d6bbc290611deb9085908590600401613f67565b8015611e1957604051634b8a352960e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690634b8a352990611deb9085908590600401613f67565b60008061355a85856135d5565b61356487856135d5565b10613580576135758686868661360f565b915060009050613593565b61358c8587858761360f565b9150600190505b94509492505050565b606083156135ab575081611c4b565b8251156135bb5782518084602001fd5b8160405162461bcd60e51b815260040161019c9190613fc1565b6000826135e45750600061069a565b828202828482816135f157fe5b04146106975760405162461bcd60e51b815260040161019c906142a6565b600061361b84846135d5565b61362586846135d5565b10156136435760405162461bcd60e51b815260040161019c90614330565b6103e560006136546107cd866135d5565b9050600061366f61366588886135d5565b6121868a886135d5565b9050600061369c876136966136848b8a61336c565b613690866103e86135d5565b90613709565b906135d5565b905060006136af600461369687856135d5565b905060006136cf6136ca836136c488806135d5565b9061336c565b61373b565b905060006136dd8287613344565b905060006136ec8860026135d5565b90506136f88282613709565b9d9c50505050505050505050505050565b600080821161372a5760405162461bcd60e51b815260040161019c90614141565b81838161373357fe5b049392505050565b60008161374a57506000610467565b816001600160801b82106137635760809190911c9060401b5b68010000000000000000821061377e5760409190911c9060201b5b64010000000082106137955760209190911c9060101b5b6201000082106137aa5760109190911c9060081b5b61010082106137be5760089190911c9060041b5b601082106137d15760049190911c9060021b5b600882106137dd5760011b5b60018185816137e857fe5b048201901c905060018185816137fa57fe5b048201901c9050600181858161380c57fe5b048201901c9050600181858161381e57fe5b048201901c9050600181858161383057fe5b048201901c9050600181858161384257fe5b048201901c9050600181858161385457fe5b048201901c9050600081858161386657fe5b0490508082106138765780613878565b815b95945050505050565b60008083601f840112613892578182fd5b50813567ffffffffffffffff8111156138a9578182fd5b60208301915083602080830285010111156138c357600080fd5b9250929050565b60008083601f8401126138db578182fd5b50813567ffffffffffffffff8111156138f2578182fd5b6020830191508360208285010111156138c357600080fd5b6000610100828403121561391c578081fd5b50919050565b600060208284031215613933578081fd5b81356106978161455b565b60006020828403121561394f578081fd5b81516106978161455b565b6000806040838503121561396c578081fd5b82356139778161455b565b915060208301356139878161455b565b809150509250929050565b60008060008060008060008060a0898b0312156139ad578384fd5b88356139b88161455b565b975060208901356139c88161455b565b9650604089013567ffffffffffffffff808211156139e4578586fd5b6139f08c838d01613881565b909850965060608b0135915080821115613a08578586fd5b613a148c838d01613881565b909650945060808b0135915080821115613a2c578384fd5b50613a398b828c016138ca565b999c989b5096995094979396929594505050565b60008060006101408486031215613a62578283fd5b8335613a6d8161455b565b92506020840135613a7d8161455b565b9150613a8c856040860161390a565b90509250925092565b6000806000806101608587031215613aab578384fd5b8435613ab68161455b565b93506020850135613ac68161455b565b9250613ad5866040870161390a565b939692955092936101400135925050565b6000806000838503610120811215613afc578384fd5b8435613b078161455b565b93506020850135613b178161455b565b925060e0603f1982011215613b2a578182fd5b506040840190509250925092565b60008060008060808587031215613b4d578182fd5b8451613b588161455b565b6020860151909450613b698161455b565b6040860151606090960151949790965092505050565b60008060008060008060a08789031215613b97578384fd5b8635613ba28161455b565b95506020870135613bb28161455b565b94506040870135935060608701359250608087013567ffffffffffffffff811115613bdb578283fd5b613be789828a016138ca565b979a9699509497509295939492505050565b60008060008060808587031215613c0e578182fd5b8451613c198161455b565b60208601516040870151606090970151919890975090945092505050565b60008060008060408587031215613c4c578182fd5b843567ffffffffffffffff80821115613c63578384fd5b613c6f88838901613881565b90965094506020870135915080821115613c87578384fd5b50613c9487828801613881565b95989497509550505050565b60006020808385031215613cb2578182fd5b825167ffffffffffffffff811115613cc8578283fd5b8301601f81018513613cd8578283fd5b8051613ceb613ce68261450f565b6144e8565b8181528381019083850185840285018601891015613d07578687fd5b8694505b83851015613d29578051835260019490940193918501918501613d0b565b50979650505050505050565b600060208284031215613d46578081fd5b813561069781614570565b600060208284031215613d62578081fd5b815161069781614570565b600060208284031215613d7e578081fd5b81356001600160e01b031981168114610697578182fd5b600080600060608486031215613da9578081fd5b8351613db48161457e565b6020850151909350613dc58161457e565b604085015190925063ffffffff81168114613dde578182fd5b809150509250925092565b600060208284031215613dfa578081fd5b5051919050565b60008060408385031215613e13578182fd5b505080516020909101519092909150565b600080600060608486031215613e38578081fd5b8351925060208401519150604084015190509250925092565b6000815180845260208085019450808401835b83811015613e895781516001600160a01b031687529582019590820190600101613e64565b509495945050505050565b60008251613ea681846020870161452f565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039788168152958716602087015260408601949094526060850192909252608084015290921660a082015260c081019190915260e00190565b6001600160a01b039889168152968816602088015260408701959095526060860193909352608085019190915260a084015290921660c082015260e08101919091526101000190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b901515815260200190565b6001600160e01b031991909116815260200190565b6000602082528251806020840152613fe081604085016020870161452f565b601f01601f19169190910160400192915050565b6020808252601190820152701c99599d5b99081155120819985a5b1959607a1b604082015260600190565b60208082526018908201527f6e6f74207468652070656e64696e6720676f7665726e6f720000000000000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601b908201527f6f7261636c65206e6f7420737570706f7274206c7020746f6b656e0000000000604082015260600190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b60208082526010908201526f3737ba103a34329033b7bb32b93737b960811b604082015260600190565b60208082526025908201527f6c70546f6b656e732026207374617475736573206c656e677468206d69736d616040820152641d18da195960da1b606082015260800190565b6020808252600b908201526a3737903638103a37b5b2b760a91b604082015260600190565b60208082526012908201527134b731b7b93932b1ba103638103a37b5b2b760711b604082015260600190565b60208082526018908201527f6c7020746f6b656e206e6f742077686974656c69737465640000000000000000604082015260600190565b60208082526017908201527f455448206d75737420636f6d652066726f6d2057455448000000000000000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526029908201527f636f6c6c61746572616c20746f6b656e202620776d617374657263686566206d6040820152681a5cdb585d18da195960ba1b606082015260800190565b60208082526008908201526714995d995c9cd95960c21b604082015260600190565b6020808252600d908201526c1a5b98dbdc9c9958dd081c1a59609a1b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b602080825260149082015273696e636f727265637420756e6465726c79696e6760601b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b90815260200190565b9182526001600160a01b0316602082015260400190565b600086825285602083015260a060408301526144bd60a0830186613e51565b6001600160a01b0394909416606083015250608001529392505050565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561450757600080fd5b604052919050565b600067ffffffffffffffff821115614525578081fd5b5060209081020190565b60005b8381101561454a578181015183820152602001614532565b838111156104ca5750506000910152565b6001600160a01b03811681146131f157600080fd5b80151581146131f157600080fd5b6001600160701b03811681146131f157600080fdfea2646970667358221220d5c29f7024c1786530ba760dd3ab0666c5d8eb0af8bb5acc5509dbf76873090064736f6c634300060c0033000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a3000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb60

Deployed Bytecode

0x60806040526004361061014f5760003560e01c806395723b1c116100b6578063e58bb6391161006f578063e58bb6391461039f578063ee42c6f4146103b4578063f235757f146103d4578063f23a6e61146103f4578063f4b1604514610414578063f887ea4014610434576101a7565b806395723b1c14610302578063bc197c8114610322578063c45a01551461034f578063cc9b188014610364578063e07d904e14610377578063e3056a341461038a576101a7565b806340a65ad21161010857806340a65ad21461026e5780634bab09f6146102835780635741229c146102a357806369454b86146102b857806376cdb03b146102d857806386adcc79146102ed576101a7565b806301ffc9a7146101ac5780630a087903146101e25780630c340a24146102045780631387d96d146102195780632185059f146102395780633fc8cef314610259576101a7565b366101a757336001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216146101a55760405162461bcd60e51b815260040161019c9061426f565b60405180910390fd5b005b600080fd5b3480156101b857600080fd5b506101cc6101c7366004613d6d565b610449565b6040516101d99190613fa1565b60405180910390f35b3480156101ee57600080fd5b506101f761046c565b6040516101d99190613eb0565b34801561021057600080fd5b506101f7610490565b34801561022557600080fd5b506101a5610234366004613ae6565b6104a5565b34801561024557600080fd5b506101f761025436600461395a565b6104d0565b34801561026557600080fd5b506101f76106a0565b34801561027a57600080fd5b506101a56106c4565b34801561028f57600080fd5b506101cc61029e366004613922565b610c93565b3480156102af57600080fd5b506101f7610ca8565b3480156102c457600080fd5b506101f76102d336600461395a565b610ccc565b3480156102e457600080fd5b506101f7610cf2565b3480156102f957600080fd5b506101f7610d16565b34801561030e57600080fd5b506101a561031d366004613ae6565b610d3a565b34801561032e57600080fd5b5061034261033d366004613992565b611059565b6040516101d99190613fac565b34801561035b57600080fd5b506101f761106d565b6101a5610372366004613a4d565b611091565b6101a5610385366004613a95565b61114a565b34801561039657600080fd5b506101f76117e4565b3480156103ab57600080fd5b506101a56117f3565b3480156103c057600080fd5b506101a56103cf366004613c37565b611883565b3480156103e057600080fd5b506101a56103ef366004613922565b611a58565b34801561040057600080fd5b5061034261040f366004613b7f565b611ade565b34801561042057600080fd5b506101cc61042f36600461395a565b611af0565b34801561044057600080fd5b506101f7611b10565b6001600160e01b0319811660009081526020819052604090205460ff165b919050565b7f0000000000000000000000006b3595068778dd592e39a122f4f5a5cf09c90fe281565b6042546201000090046001600160a01b031681565b60006104b184846104d0565b90506104be818335611c52565b6104ca84848484611e1d565b50505050565b6001600160a01b0380831660009081526085602090815260408083208585168452909152812054909116806106975760405163e6a4390560e01b81526001600160a01b037f000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac169063e6a439059061054d9087908790600401613ec4565b60206040518083038186803b15801561056557600080fd5b505afa158015610579573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059d919061393e565b90506001600160a01b0381166105c55760405162461bcd60e51b815260040161019c906141e7565b6105ef847f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f6126b8565b610619837f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f6126b8565b610643817f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f6126b8565b6001600160a01b0380851660008181526085602081815260408084208987168552825280842080549688166001600160a01b0319978816811790915592825280842094845293905291902080549092161790555b90505b92915050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6000807f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b15801561072057600080fd5b505afa158015610734573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107589190613b38565b50925092505060007f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606001600160a01b031663dc20c6fa836040518263ffffffff1660e01b81526004016107ac919061447e565b604080518083038186803b1580156107c357600080fd5b505afa1580156107d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fb9190613e01565b50905060007f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606001600160a01b031663a4775772846040518263ffffffff1660e01b815260040161084c919061447e565b60206040518083038186803b15801561086457600080fd5b505afa158015610878573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089c919061393e565b6001600160a01b03811660009081526084602052604090205490915060ff166108d75760405162461bcd60e51b815260040161019c90614238565b7f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606001600160a01b0316846001600160a01b0316146109285760405162461bcd60e51b815260040161019c906142e7565b604051630d1d697560e31b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906368eb4ba89061099a907f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb6090879060001990600401613f80565b600060405180830381600087803b1580156109b457600080fd5b505af11580156109c8573d6000803e3d6000fd5b505060405163b390c0ab60e01b81526001600160a01b037f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb6016925063b390c0ab9150610a1c908690600019906004016144da565b602060405180830381600087803b158015610a3657600080fd5b505af1158015610a4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6e9190613de9565b506040516370a0823160e01b81526000906001600160a01b038316906370a0823190610a9e903090600401613eb0565b60206040518083038186803b158015610ab657600080fd5b505afa158015610aca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aee9190613de9565b9050610b1a827f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606126b8565b604051630d9778e560e11b81526000906001600160a01b037f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb601690631b2ef1ca90610b6b90879086906004016144da565b602060405180830381600087803b158015610b8557600080fd5b505af1158015610b99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbd9190613de9565b60405163314568d960e01b81529091506001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b169063314568d990610c30907f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb609085908790600401613f80565b600060405180830381600087803b158015610c4a57600080fd5b505af1158015610c5e573d6000803e3d6000fd5b50505050610c8b7f0000000000000000000000006b3595068778dd592e39a122f4f5a5cf09c90fe261272f565b505050505050565b60846020526000908152604090205460ff1681565b7f00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a381565b60856020908152600092835260408084209091529082529020546001600160a01b031681565b7f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b81565b7f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb6081565b6000610d4684846104d0565b90506000807f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b158015610da457600080fd5b505afa158015610db8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ddc9190613b38565b509250925050826001600160a01b0316826001600160a01b031663a4775772836040518263ffffffff1660e01b8152600401610e18919061447e565b60206040518083038186803b158015610e3057600080fd5b505afa158015610e44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e68919061393e565b6001600160a01b031614610e8e5760405162461bcd60e51b815260040161019c906143b0565b7f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606001600160a01b0316826001600160a01b031614610edf5760405162461bcd60e51b815260040161019c906142e7565b604051630d1d697560e31b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906368eb4ba890610f50907f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb60908590893590600401613f80565b600060405180830381600087803b158015610f6a57600080fd5b505af1158015610f7e573d6000803e3d6000fd5b505060405163b390c0ab60e01b81526001600160a01b037f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb6016925063b390c0ab9150610fd19084908835906004016144da565b602060405180830381600087803b158015610feb57600080fd5b505af1158015610fff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110239190613de9565b5061103086868686611e1d565b610c8b7f0000000000000000000000006b3595068778dd592e39a122f4f5a5cf09c90fe261272f565b63bc197c8160e01b98975050505050505050565b7f000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac81565b600061109d84846104d0565b90506110ab8484848461285b565b61113081826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016110db9190613eb0565b60206040518083038186803b1580156110f357600080fd5b505afa158015611107573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112b9190613de9565b612e89565b611138612fab565b6111418461272f565b6104ca8361272f565b600061115685856104d0565b905060007f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606001600160a01b0316631fc8bc5d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156111b357600080fd5b505afa1580156111c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111eb919061393e565b6001600160a01b0316631526fe27846040518263ffffffff1660e01b8152600401611216919061447e565b60806040518083038186803b15801561122e57600080fd5b505afa158015611242573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112669190613bf9565b5050509050816001600160a01b0316816001600160a01b03161461129c5760405162461bcd60e51b815260040161019c9061420c565b6112a88686868561285b565b60008060007f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b15801561130657600080fd5b505afa15801561131a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133e9190613b38565b919550935091505080156115a257604051636e10637d60e11b81526000906001600160a01b037f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb60169063dc20c6fa9061139b90869060040161447e565b604080518083038186803b1580156113b257600080fd5b505afa1580156113c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ea9190613e01565b50905080871461140c5760405162461bcd60e51b815260040161019c90614352565b7f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606001600160a01b0316846001600160a01b03161461145d5760405162461bcd60e51b815260040161019c906142e7565b604051630d1d697560e31b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906368eb4ba8906114cd907f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb609087908790600401613f80565b600060405180830381600087803b1580156114e757600080fd5b505af11580156114fb573d6000803e3d6000fd5b505060405163b390c0ab60e01b81526001600160a01b037f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb6016925063b390c0ab915061154d90869086906004016144da565b602060405180830381600087803b15801561156757600080fd5b505af115801561157b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159f9190613de9565b50505b6115cc857f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606126b8565b6040516370a0823160e01b81526000906001600160a01b038716906370a08231906115fb903090600401613eb0565b60206040518083038186803b15801561161357600080fd5b505afa158015611627573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061164b9190613de9565b905060007f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606001600160a01b0316631b2ef1ca89846040518363ffffffff1660e01b815260040161169d9291906144da565b602060405180830381600087803b1580156116b757600080fd5b505af11580156116cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ef9190613de9565b60405163314568d960e01b81529091506001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b169063314568d990611762907f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb609085908790600401613f80565b600060405180830381600087803b15801561177c57600080fd5b505af1158015611790573d6000803e3d6000fd5b5050505061179c612fab565b6117a58b61272f565b6117ae8a61272f565b6117d77f0000000000000000000000006b3595068778dd592e39a122f4f5a5cf09c90fe261272f565b5050505050505050505050565b6043546001600160a01b031681565b6043546001600160a01b0316331461181d5760405162461bcd60e51b815260040161019c9061401f565b604380546001600160a01b03191690556042805462010000600160b01b03191633620100008102919091179091556040517fd345d81ce68c70b119a17eee79dc1421700bd9cb21ca148a62dc90983964e82f9161187991613eb0565b60405180910390a1565b6042546201000090046001600160a01b031633146118b35760405162461bcd60e51b815260040161019c90614178565b8281146118d25760405162461bcd60e51b815260040161019c906141a2565b60005b83811015611a51578282828181106118e957fe5b90506020020160208101906118fe9190613d35565b156119db577f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663e660cc0886868481811061193e57fe5b90506020020160208101906119539190613922565b6040518263ffffffff1660e01b815260040161196f9190613eb0565b60206040518083038186803b15801561198757600080fd5b505afa15801561199b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119bf9190613d51565b6119db5760405162461bcd60e51b815260040161019c9061408d565b8282828181106119e757fe5b90506020020160208101906119fc9190613d35565b60846000878785818110611a0c57fe5b9050602002016020810190611a219190613922565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790556001016118d5565b5050505050565b6042546201000090046001600160a01b03163314611a885760405162461bcd60e51b815260040161019c90614178565b604380546001600160a01b0319166001600160a01b0383161790556040517f964dea888b00b2ab53f13dfe7ca334b46e99338c222ae232d98547a1da019f6090611ad3908390613eb0565b60405180910390a150565b63f23a6e6160e01b9695505050505050565b604160209081526000928352604080842090915290825290205460ff1681565b7f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f81565b801580611bbc5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90611b6a9030908690600401613ec4565b60206040518083038186803b158015611b8257600080fd5b505afa158015611b96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bba9190613de9565b155b611bd85760405162461bcd60e51b815260040161019c90614428565b611c2e8363095ea7b360e01b8484604051602401611bf7929190613f67565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526131f4565b505050565b3b151590565b6060611c488484600085613283565b90505b9392505050565b8015611e1957600019811415611cf9577f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b158015611cbb57600080fd5b505afa158015611ccf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf39190613b38565b93505050505b604051630d1d697560e31b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b8116916368eb4ba891611d6b917f00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a3918716908690600401613f80565b600060405180830381600087803b158015611d8557600080fd5b505af1158015611d99573d6000803e3d6000fd5b5050604051632770a7eb60e21b81526001600160a01b037f00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a3169250639dc29fac9150611deb9085908590600401613f67565b600060405180830381600087803b158015611e0557600080fd5b505af1158015610c8b573d6000803e3d6000fd5b5050565b6001600160a01b03811660009081526084602052604090205460ff16611e555760405162461bcd60e51b815260040161019c90614238565b60007f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663d7ac71ff6040518163ffffffff1660e01b815260040160206040518083038186803b158015611eb057600080fd5b505afa158015611ec4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee89190613de9565b9050604083013560608401356080850135600019831415611fa6576040516320a8bee760e21b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906382a2fb9c90611f519087908c90600401614487565b602060405180830381600087803b158015611f6b57600080fd5b505af1158015611f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa39190613de9565b92505b600019821415612053576040516320a8bee760e21b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906382a2fb9c90611ffe9087908b90600401614487565b602060405180830381600087803b15801561201857600080fd5b505af115801561202c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120509190613de9565b91505b600019811415612100576040516320a8bee760e21b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906382a2fb9c906120ab9087908990600401614487565b602060405180830381600087803b1580156120c557600080fd5b505af11580156120d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fd9190613de9565b90505b600061218c8760200135876001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016121369190613eb0565b60206040518083038186803b15801561214e57600080fd5b505afa158015612162573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121869190613de9565b90613344565b9050600080821561224757604051635d5155ef60e11b81526001600160a01b037f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f169063baa2abde906121f0908e908e908890600090819030904290600401613ede565b6040805180830381600087803b15801561220957600080fd5b505af115801561221d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122419190613e01565b90925090505b60006122578760a08c013561336c565b905060006122698760c08d013561336c565b9050818410801561227957508083115b156123985760408051600280825260608083018452926020830190803683370190505090508c8e826000815181106122ad57fe5b60200260200101836001815181106122c157fe5b6001600160a01b0393841660209182029290920101529181169091527f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f16638803dbee61230e8588613344565b6123188786613344565b8430426040518663ffffffff1660e01b815260040161233b95949392919061449e565b600060405180830381600087803b15801561235557600080fd5b505af1158015612369573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526123919190810190613ca0565b50506124c1565b81841180156123a657508083105b156124c15760408051600280825260608083018452926020830190803683370190505090508d8d826000815181106123da57fe5b60200260200101836001815181106123ee57fe5b6001600160a01b0393841660209182029290920101529181169091527f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f16638803dbee61243b8487613344565b6124458887613344565b8430426040518663ffffffff1660e01b815260040161246895949392919061449e565b600060405180830381600087803b15801561248257600080fd5b505af1158015612496573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526124be9190810190613ca0565b50505b6124cb8d89613391565b6124d58c88613391565b6124df8a87613391565b6040516370a0823160e01b815260a08c0135906001600160a01b038f16906370a0823190612511903090600401613eb0565b60206040518083038186803b15801561252957600080fd5b505afa15801561253d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125619190613de9565b101561256c57600080fd5b6040516370a0823160e01b815260c08c0135906001600160a01b038e16906370a082319061259e903090600401613eb0565b60206040518083038186803b1580156125b657600080fd5b505afa1580156125ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ee9190613de9565b10156125f957600080fd5b6040516370a0823160e01b815260208c0135906001600160a01b038c16906370a082319061262b903090600401613eb0565b60206040518083038186803b15801561264357600080fd5b505afa158015612657573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061267b9190613de9565b101561268657600080fd5b61268e612fab565b6126978d61272f565b6126a08c61272f565b6126a98a61272f565b50505050505050505050505050565b6001600160a01b0380831660009081526041602090815260408083209385168352929052205460ff16611e19576126fb6001600160a01b03831682600019611b34565b6001600160a01b038083166000908152604160209081526040808320938516835292905220805460ff191660011790555050565b6040516370a0823160e01b81526000906001600160a01b038316906370a082319061275e903090600401613eb0565b60206040518083038186803b15801561277657600080fd5b505afa15801561278a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ae9190613de9565b90508015611e1957611e197f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663630dc7cb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561281257600080fd5b505afa158015612826573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284a919061393e565b6001600160a01b038416908361340f565b6001600160a01b03811660009081526084602052604090205460ff166128935760405162461bcd60e51b815260040161019c90614238565b61289b61342e565b6128a68483356134a5565b6128b48383602001356134a5565b6128c28183604001356134a5565b6128d08483606001356134f9565b6128de8383608001356134f9565b6128ec818360a001356134f9565b6000806000866001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161291d9190613eb0565b60206040518083038186803b15801561293557600080fd5b505afa158015612949573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296d9190613de9565b90506000866001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161299d9190613eb0565b60206040518083038186803b1580156129b557600080fd5b505afa1580156129c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ed9190613de9565b9050600080896001600160a01b0316876001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b158015612a3557600080fd5b505afa158015612a49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6d919061393e565b6001600160a01b03161415612b0357866001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015612ab557600080fd5b505afa158015612ac9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aed9190613d95565b506001600160701b039182169350169050612b86565b866001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015612b3c57600080fd5b505afa158015612b50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b749190613d95565b506001600160701b0390811693501690505b612b928484848461354d565b90965094505084159250612cb791505057604080516002808252606080830184529260208301908036833701905050905081612bcf578686612bd2565b85875b82600081518110612bdf57fe5b6020026020010183600181518110612bf357fe5b6001600160a01b0393841660209182029290920101529181169091526040516338ed173960e01b81527f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f909116906338ed173990612c5e90869060009086903090429060040161449e565b600060405180830381600087803b158015612c7857600080fd5b505af1158015612c8c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612cb49190810190613ca0565b50505b6040516370a0823160e01b81526000906001600160a01b038816906370a0823190612ce6903090600401613eb0565b60206040518083038186803b158015612cfe57600080fd5b505afa158015612d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d369190613de9565b90506000866001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612d669190613eb0565b60206040518083038186803b158015612d7e57600080fd5b505afa158015612d92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612db69190613de9565b90506000821180612dc75750600081115b15612e7f5760405162e8e33760e81b81526001600160a01b037f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f169063e8e3370090612e2d908b908b908790879060c08e01359060e08f01359030904290600401613f1e565b606060405180830381600087803b158015612e4757600080fd5b505af1158015612e5b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d79190613e24565b5050505050505050565b8015611e1957612eb9827f00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a36126b8565b6040516340c10f1960e01b81526001600160a01b037f00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a316906340c10f1990612f079085908590600401613f67565b600060405180830381600087803b158015612f2157600080fd5b505af1158015612f35573d6000803e3d6000fd5b505060405163314568d960e01b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b8116935063314568d99250611deb917f00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a3918716908690600401613f80565b6040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216906370a0823190612ffa903090600401613eb0565b602060405180830381600087803b15801561301457600080fd5b505af1158015613028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304c9190613de9565b905080156131f157604051632e1a7d4d60e01b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21690632e1a7d4d906130a090849060040161447e565b600060405180830381600087803b1580156130ba57600080fd5b505af11580156130ce573d6000803e3d6000fd5b5050505060007f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663630dc7cb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561312d57600080fd5b505afa158015613141573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613165919061393e565b604080516000815260208101918290526001600160a01b039290921691849161318e9190613e94565b60006040518083038185875af1925050503d80600081146131cb576040519150601f19603f3d011682016040523d82523d6000602084013e6131d0565b606091505b5050905080611e195760405162461bcd60e51b815260040161019c90613ff4565b50565b6060613249826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611c399092919063ffffffff16565b805190915015611c2e57808060200190518101906132679190613d51565b611c2e5760405162461bcd60e51b815260040161019c906143de565b6060824710156132a55760405162461bcd60e51b815260040161019c906140fb565b6132ae85611c33565b6132ca5760405162461bcd60e51b815260040161019c90614379565b60006060866001600160a01b031685876040516132e79190613e94565b60006040518083038185875af1925050503d8060008114613324576040519150601f19603f3d011682016040523d82523d6000602084013e613329565b606091505b509150915061333982828661359c565b979650505050505050565b6000828211156133665760405162461bcd60e51b815260040161019c906140c4565b50900390565b6000828201838110156106975760405162461bcd60e51b815260040161019c90614056565b8015611e19576133c1827f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6126b8565b604051630450cfaf60e31b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906322867d7890611deb9085908590600401613f67565b611c2e8363a9059cbb60e01b8484604051602401611bf7929190613f67565b34156134a3577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561348f57600080fd5b505af1158015611a51573d6000803e3d6000fd5b565b8015611e195760405163246b5de160e11b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906348d6bbc290611deb9085908590600401613f67565b8015611e1957604051634b8a352960e01b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b1690634b8a352990611deb9085908590600401613f67565b60008061355a85856135d5565b61356487856135d5565b10613580576135758686868661360f565b915060009050613593565b61358c8587858761360f565b9150600190505b94509492505050565b606083156135ab575081611c4b565b8251156135bb5782518084602001fd5b8160405162461bcd60e51b815260040161019c9190613fc1565b6000826135e45750600061069a565b828202828482816135f157fe5b04146106975760405162461bcd60e51b815260040161019c906142a6565b600061361b84846135d5565b61362586846135d5565b10156136435760405162461bcd60e51b815260040161019c90614330565b6103e560006136546107cd866135d5565b9050600061366f61366588886135d5565b6121868a886135d5565b9050600061369c876136966136848b8a61336c565b613690866103e86135d5565b90613709565b906135d5565b905060006136af600461369687856135d5565b905060006136cf6136ca836136c488806135d5565b9061336c565b61373b565b905060006136dd8287613344565b905060006136ec8860026135d5565b90506136f88282613709565b9d9c50505050505050505050505050565b600080821161372a5760405162461bcd60e51b815260040161019c90614141565b81838161373357fe5b049392505050565b60008161374a57506000610467565b816001600160801b82106137635760809190911c9060401b5b68010000000000000000821061377e5760409190911c9060201b5b64010000000082106137955760209190911c9060101b5b6201000082106137aa5760109190911c9060081b5b61010082106137be5760089190911c9060041b5b601082106137d15760049190911c9060021b5b600882106137dd5760011b5b60018185816137e857fe5b048201901c905060018185816137fa57fe5b048201901c9050600181858161380c57fe5b048201901c9050600181858161381e57fe5b048201901c9050600181858161383057fe5b048201901c9050600181858161384257fe5b048201901c9050600181858161385457fe5b048201901c9050600081858161386657fe5b0490508082106138765780613878565b815b95945050505050565b60008083601f840112613892578182fd5b50813567ffffffffffffffff8111156138a9578182fd5b60208301915083602080830285010111156138c357600080fd5b9250929050565b60008083601f8401126138db578182fd5b50813567ffffffffffffffff8111156138f2578182fd5b6020830191508360208285010111156138c357600080fd5b6000610100828403121561391c578081fd5b50919050565b600060208284031215613933578081fd5b81356106978161455b565b60006020828403121561394f578081fd5b81516106978161455b565b6000806040838503121561396c578081fd5b82356139778161455b565b915060208301356139878161455b565b809150509250929050565b60008060008060008060008060a0898b0312156139ad578384fd5b88356139b88161455b565b975060208901356139c88161455b565b9650604089013567ffffffffffffffff808211156139e4578586fd5b6139f08c838d01613881565b909850965060608b0135915080821115613a08578586fd5b613a148c838d01613881565b909650945060808b0135915080821115613a2c578384fd5b50613a398b828c016138ca565b999c989b5096995094979396929594505050565b60008060006101408486031215613a62578283fd5b8335613a6d8161455b565b92506020840135613a7d8161455b565b9150613a8c856040860161390a565b90509250925092565b6000806000806101608587031215613aab578384fd5b8435613ab68161455b565b93506020850135613ac68161455b565b9250613ad5866040870161390a565b939692955092936101400135925050565b6000806000838503610120811215613afc578384fd5b8435613b078161455b565b93506020850135613b178161455b565b925060e0603f1982011215613b2a578182fd5b506040840190509250925092565b60008060008060808587031215613b4d578182fd5b8451613b588161455b565b6020860151909450613b698161455b565b6040860151606090960151949790965092505050565b60008060008060008060a08789031215613b97578384fd5b8635613ba28161455b565b95506020870135613bb28161455b565b94506040870135935060608701359250608087013567ffffffffffffffff811115613bdb578283fd5b613be789828a016138ca565b979a9699509497509295939492505050565b60008060008060808587031215613c0e578182fd5b8451613c198161455b565b60208601516040870151606090970151919890975090945092505050565b60008060008060408587031215613c4c578182fd5b843567ffffffffffffffff80821115613c63578384fd5b613c6f88838901613881565b90965094506020870135915080821115613c87578384fd5b50613c9487828801613881565b95989497509550505050565b60006020808385031215613cb2578182fd5b825167ffffffffffffffff811115613cc8578283fd5b8301601f81018513613cd8578283fd5b8051613ceb613ce68261450f565b6144e8565b8181528381019083850185840285018601891015613d07578687fd5b8694505b83851015613d29578051835260019490940193918501918501613d0b565b50979650505050505050565b600060208284031215613d46578081fd5b813561069781614570565b600060208284031215613d62578081fd5b815161069781614570565b600060208284031215613d7e578081fd5b81356001600160e01b031981168114610697578182fd5b600080600060608486031215613da9578081fd5b8351613db48161457e565b6020850151909350613dc58161457e565b604085015190925063ffffffff81168114613dde578182fd5b809150509250925092565b600060208284031215613dfa578081fd5b5051919050565b60008060408385031215613e13578182fd5b505080516020909101519092909150565b600080600060608486031215613e38578081fd5b8351925060208401519150604084015190509250925092565b6000815180845260208085019450808401835b83811015613e895781516001600160a01b031687529582019590820190600101613e64565b509495945050505050565b60008251613ea681846020870161452f565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039788168152958716602087015260408601949094526060850192909252608084015290921660a082015260c081019190915260e00190565b6001600160a01b039889168152968816602088015260408701959095526060860193909352608085019190915260a084015290921660c082015260e08101919091526101000190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b901515815260200190565b6001600160e01b031991909116815260200190565b6000602082528251806020840152613fe081604085016020870161452f565b601f01601f19169190910160400192915050565b6020808252601190820152701c99599d5b99081155120819985a5b1959607a1b604082015260600190565b60208082526018908201527f6e6f74207468652070656e64696e6720676f7665726e6f720000000000000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601b908201527f6f7261636c65206e6f7420737570706f7274206c7020746f6b656e0000000000604082015260600190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b60208082526010908201526f3737ba103a34329033b7bb32b93737b960811b604082015260600190565b60208082526025908201527f6c70546f6b656e732026207374617475736573206c656e677468206d69736d616040820152641d18da195960da1b606082015260800190565b6020808252600b908201526a3737903638103a37b5b2b760a91b604082015260600190565b60208082526012908201527134b731b7b93932b1ba103638103a37b5b2b760711b604082015260600190565b60208082526018908201527f6c7020746f6b656e206e6f742077686974656c69737465640000000000000000604082015260600190565b60208082526017908201527f455448206d75737420636f6d652066726f6d2057455448000000000000000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526029908201527f636f6c6c61746572616c20746f6b656e202620776d617374657263686566206d6040820152681a5cdb585d18da195960ba1b606082015260800190565b60208082526008908201526714995d995c9cd95960c21b604082015260600190565b6020808252600d908201526c1a5b98dbdc9c9958dd081c1a59609a1b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b602080825260149082015273696e636f727265637420756e6465726c79696e6760601b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b90815260200190565b9182526001600160a01b0316602082015260400190565b600086825285602083015260a060408301526144bd60a0830186613e51565b6001600160a01b0394909416606083015250608001529392505050565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561450757600080fd5b604052919050565b600067ffffffffffffffff821115614525578081fd5b5060209081020190565b60005b8381101561454a578181015183820152602001614532565b838111156104ca5750506000910152565b6001600160a01b03811681146131f157600080fd5b80151581146131f157600080fd5b6001600160701b03811681146131f157600080fdfea2646970667358221220d5c29f7024c1786530ba760dd3ab0666c5d8eb0af8bb5acc5509dbf76873090064736f6c634300060c0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a3000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb60

-----Decoded View---------------
Arg [0] : _bank (address): 0xba5eBAf3fc1Fcca67147050Bf80462393814E54B
Arg [1] : _werc20 (address): 0x06799a1e4792001AA9114F0012b9650cA28059a3
Arg [2] : _router (address): 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F
Arg [3] : _wmasterchef (address): 0xA2caEa05fF7B98f10Ad5ddc837F15905f33FEb60

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b
Arg [1] : 00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a3
Arg [2] : 000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f
Arg [3] : 000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb60


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.