ETH Price: $1,987.42 (-4.28%)

Contract

0x39816B841436a57729723d9DA127805755d2CB51
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Fee Receiver126179472021-06-12 5:51:241383 days ago1623477084IN
0x39816B84...755d2CB51
0 ETH0.0007575225
Set DAO126179462021-06-12 5:50:261383 days ago1623477026IN
0x39816B84...755d2CB51
0 ETH0.0007564225
Set Fee Receiver126116682021-06-11 6:31:071384 days ago1623393067IN
0x39816B84...755d2CB51
0 ETH0.0007575225
Set DAO126116672021-06-11 6:30:421384 days ago1623393042IN
0x39816B84...755d2CB51
0 ETH0.0007564225
Set Controller125720662021-06-05 3:25:241390 days ago1622863524IN
0x39816B84...755d2CB51
0 ETH0.0005448718
Set Trade Mining...124495122021-05-17 3:27:041409 days ago1621222024IN
0x39816B84...755d2CB51
0 ETH0.0041757390
Set Trade Mining...124495092021-05-17 3:26:071409 days ago1621221967IN
0x39816B84...755d2CB51
0 ETH0.0041757390
Set Trade Mining...124495072021-05-17 3:26:001409 days ago1621221960IN
0x39816B84...755d2CB51
0 ETH0.0041757390
Create Pair124495012021-05-17 3:24:591409 days ago1621221899IN
0x39816B84...755d2CB51
0 ETH0.2929307490
Create Pair124494992021-05-17 3:24:501409 days ago1621221890IN
0x39816B84...755d2CB51
0 ETH0.2929296690
Create Pair124494972021-05-17 3:24:271409 days ago1621221867IN
0x39816B84...755d2CB51
0 ETH0.2944643490
Set Fee Receiver124494692021-05-17 3:17:481409 days ago1621221468IN
0x39816B84...755d2CB51
0 ETH0.0027281790
Set DAO124494682021-05-17 3:17:411409 days ago1621221461IN
0x39816B84...755d2CB51
0 ETH0.0042632190
Set Vault For C ...124494662021-05-17 3:17:081409 days ago1621221428IN
0x39816B84...755d2CB51
0 ETH0.0042692490
Set Vault For Tr...124494632021-05-17 3:16:541409 days ago1621221414IN
0x39816B84...755d2CB51
0 ETH0.004263390
Set Vault For LP124494552021-05-17 3:15:381409 days ago1621221338IN
0x39816B84...755d2CB51
0 ETH0.0042693390
Set Controller124494532021-05-17 3:15:251409 days ago1621221325IN
0x39816B84...755d2CB51
0 ETH0.0042633990

Latest 3 internal transactions

Advanced mode:
Parent Transaction Hash Method Block
From
To
-124495012021-05-17 3:24:591409 days ago1621221899
0x39816B84...755d2CB51
 Contract Creation0 ETH
-124494992021-05-17 3:24:501409 days ago1621221890
0x39816B84...755d2CB51
 Contract Creation0 ETH
-124494972021-05-17 3:24:271409 days ago1621221867
0x39816B84...755d2CB51
 Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CoFiXV2Factory

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 6666 runs

Other Settings:
istanbul EvmVersion, GNU GPLv3 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2021-05-17
*/

// File: contracts/interface/ICoFiXV2DAO.sol

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity 0.6.12;

interface ICoFiXV2DAO {

    function setGovernance(address gov) external;
    function start() external; 

    // function addETHReward() external payable; 

    event FlagSet(address gov, uint256 flag);
    event CoFiBurn(address gov, uint256 amount);
}
// File: contracts/lib/TransferHelper.sol

pragma solidity 0.6.12;

// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
    function safeApprove(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
    }

    function safeTransfer(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
    }

    function safeTransferFrom(address token, address from, address to, uint value) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
    }

    function safeTransferETH(address to, uint value) internal {
        (bool success,) = to.call{value:value}(new bytes(0));
        require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
    }
}

// File: @openzeppelin/contracts/math/SafeMath.sol

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, 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;
    }
}

// File: @openzeppelin/contracts/token/ERC20/IERC20.sol

pragma solidity >=0.6.0 <0.8.0;

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

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

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

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

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

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

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

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

// File: contracts/interface/IWETH.sol

pragma solidity 0.6.12;

interface IWETH {
    function deposit() external payable;
    function transfer(address to, uint value) external returns (bool);
    function withdraw(uint) external;
    function balanceOf(address account) external view returns (uint);
}

// File: contracts/interface/ICoFiXERC20.sol

pragma solidity 0.6.12;

interface ICoFiXERC20 {
    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;
}

// File: contracts/interface/ICoFiXV2Pair.sol

pragma solidity 0.6.12;

interface ICoFiXV2Pair is ICoFiXERC20 {

    struct OraclePrice {
        uint256 ethAmount;
        uint256 erc20Amount;
        uint256 blockNum;
        uint256 K;
        uint256 theta;
    }

    // All pairs: {ETH <-> ERC20 Token}
    event Mint(address indexed sender, uint amount0, uint amount1);
    event Burn(address indexed sender, address outToken, uint outAmount, address indexed to);
    event Swap(
        address indexed sender,
        uint amountIn,
        uint amountOut,
        address outToken,
        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);

    function mint(address to, uint amountETH, uint amountToken) external payable returns (uint liquidity, uint oracleFeeChange);
    function burn(address tokenTo, address ethTo) external payable returns (uint amountTokenOut, uint amountETHOut, uint oracleFeeChange);
    function swapWithExact(address outToken, address to) external payable returns (uint amountIn, uint amountOut, uint oracleFeeChange, uint256[5] memory tradeInfo);
    // function swapForExact(address outToken, uint amountOutExact, address to) external payable returns (uint amountIn, uint amountOut, uint oracleFeeChange, uint256[4] memory tradeInfo);
    function skim(address to) external;
    function sync() external;

    function initialize(address, address, string memory, string memory, uint256, uint256) external;

    /// @dev get Net Asset Value Per Share
    /// @param  ethAmount ETH side of Oracle price {ETH <-> ERC20 Token}
    /// @param  erc20Amount Token side of Oracle price {ETH <-> ERC20 Token}
    /// @return navps The Net Asset Value Per Share (liquidity) represents
    function getNAVPerShare(uint256 ethAmount, uint256 erc20Amount) external view returns (uint256 navps);

    /// @dev get initial asset ratio
    /// @return _initToken0Amount Token0(ETH) side of initial asset ratio {ETH <-> ERC20 Token}
    /// @return _initToken1Amount Token1(ERC20) side of initial asset ratio {ETH <-> ERC20 Token}
    function getInitialAssetRatio() external view returns (uint256 _initToken0Amount, uint256 _initToken1Amount);
}

// File: contracts/CoFiXERC20.sol

pragma experimental ABIEncoderV2;
pragma solidity 0.6.12;

// ERC20 token implementation, inherited by CoFiXPair contract, no owner or governance
contract CoFiXERC20 is ICoFiXERC20 {
    using SafeMath for uint;

    string public constant nameForDomain = 'CoFiX Pool Token';
    uint8 public override constant decimals = 18;
    uint  public override totalSupply;
    mapping(address => uint) public override balanceOf;
    mapping(address => mapping(address => uint)) public override allowance;

    bytes32 public override DOMAIN_SEPARATOR;
    // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    bytes32 public override constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
    mapping(address => uint) public override nonces;

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

    constructor() public {
        uint chainId;
        assembly {
            chainId := chainid()
        }
        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
                keccak256(bytes(nameForDomain)),
                keccak256(bytes('1')),
                chainId,
                address(this)
            )
        );
    }

    function _mint(address to, uint value) internal {
        totalSupply = totalSupply.add(value);
        balanceOf[to] = balanceOf[to].add(value);
        emit Transfer(address(0), to, value);
    }

    function _burn(address from, uint value) internal {
        balanceOf[from] = balanceOf[from].sub(value);
        totalSupply = totalSupply.sub(value);
        emit Transfer(from, address(0), value);
    }

    function _approve(address owner, address spender, uint value) private {
        allowance[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    function _transfer(address from, address to, uint value) private {
        balanceOf[from] = balanceOf[from].sub(value);
        balanceOf[to] = balanceOf[to].add(value);
        emit Transfer(from, to, value);
    }

    function approve(address spender, uint value) external override returns (bool) {
        _approve(msg.sender, spender, value);
        return true;
    }

    function transfer(address to, uint value) external override returns (bool) {
        _transfer(msg.sender, to, value);
        return true;
    }

    function transferFrom(address from, address to, uint value) external override returns (bool) {
        if (allowance[from][msg.sender] != uint(-1)) {
            allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
        }
        _transfer(from, to, value);
        return true;
    }

    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external override {
        require(deadline >= block.timestamp, 'CERC20: EXPIRED');
        bytes32 digest = keccak256(
            abi.encodePacked(
                '\x19\x01',
                DOMAIN_SEPARATOR,
                keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
            )
        );
        address recoveredAddress = ecrecover(digest, v, r, s);
        require(recoveredAddress != address(0) && recoveredAddress == owner, 'CERC20: INVALID_SIGNATURE');
        _approve(owner, spender, value);
    }
}

// File: contracts/CoFiXV2Pair.sol

pragma solidity 0.6.12;

// Pair contract for each trading pair, storing assets and handling settlement
// No owner or governance
contract CoFiXV2Pair is ICoFiXV2Pair, CoFiXERC20 {
    using SafeMath for uint;

    enum CoFiX_OP { QUERY, MINT, BURN, SWAP_WITH_EXACT, SWAP_FOR_EXACT } // operations in CoFiX

    uint public override constant MINIMUM_LIQUIDITY = 10**9; // it's negligible because we calc liquidity in ETH
    bytes4 private constant SELECTOR = bytes4(keccak256(bytes("transfer(address,uint256)")));

    uint256 constant public K_BASE = 1E8; // K
    uint256 constant public NAVPS_BASE = 1E18; // NAVPS (Net Asset Value Per Share), need accuracy
    uint256 constant public THETA_BASE = 1E8; // theta

    string public name;
    string public symbol;

    address public override immutable factory;
    address public override token0; // WETH token
    address public override token1; // any ERC20 token

    uint112 private reserve0;           // uses single storage slot, accessible via getReserves
    uint112 private reserve1;           // uses single storage slot, accessible via getReserves

    uint256 public initToken1Amount;
    uint256 public initToken0Amount;

    uint private unlocked = 1;

    event Mint(address indexed sender, uint amount0, uint amount1);
    event Burn(address indexed sender, address outToken, uint outAmount, address indexed to);
    event Swap(
        address indexed sender,
        uint amountIn,
        uint amountOut,
        address outToken,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    modifier lock() {
        require(unlocked == 1, "CPair: LOCKED");
        unlocked = 0;
        _;
        unlocked = 1;
    }

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

    receive() external payable {}

    // called once by the factory at time of deployment
    function initialize(address _token0, address _token1, string memory _name, string memory _symbol, uint256 _initToken0Amount, uint256 _initToken1Amount) external override {
        require(msg.sender == factory, "CPair: FORBIDDEN"); // sufficient check
        token0 = _token0;
        token1 = _token1;
        name = _name;
        symbol = _symbol;
        initToken1Amount = _initToken1Amount;
        initToken0Amount = _initToken0Amount;
    }

    function getInitialAssetRatio() public override view returns (uint256 _initToken0Amount, uint256 _initToken1Amount) {
        _initToken1Amount = initToken1Amount;
        _initToken0Amount = initToken0Amount;
    }

    function getReserves() public override view returns (uint112 _reserve0, uint112 _reserve1) {
        _reserve0 = reserve0;
        _reserve1 = reserve1;
    }

    function _safeTransfer(address token, address to, uint value) private {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "CPair: TRANSFER_FAILED");
    }

    // update reserves
    function _update(uint balance0, uint balance1) private {
        require(balance0 <= uint112(-1) && balance1 <= uint112(-1), "CPair: OVERFLOW");
        reserve0 = uint112(balance0);
        reserve1 = uint112(balance1);
        emit Sync(reserve0, reserve1);
    }

    // this low-level function should be called from a contract which performs important safety checks
    function mint(address to, uint amountETH, uint amountToken) external payable override lock returns (uint liquidity, uint oracleFeeChange) {
        address _token0 = token0;                                // gas savings
        address _token1 = token1;                                // gas savings
        (uint112 _reserve0, uint112 _reserve1) = getReserves(); // gas savings
        uint balance0 = IERC20(_token0).balanceOf(address(this));
        uint balance1 = IERC20(_token1).balanceOf(address(this));
        uint amount0 = balance0.sub(_reserve0);
        uint amount1 = balance1.sub(_reserve1);

        require(amountETH <= amount0 && amountToken <= amount1, "CPair: illegal ammount");
        
        amount0 = amountETH;
        amount1 = amountToken;
        require(amount0.mul(initToken1Amount) == amount1.mul(initToken0Amount), "CPair: invalid asset ratio");
        
        uint256 _ethBalanceBefore = address(this).balance;
        { // scope for ethAmount/erc20Amount/blockNum to avoid stack too deep error
            bytes memory data = abi.encode(msg.sender, to, amount0, amount1);
            // query price
            OraclePrice memory _op;
            (_op.K, _op.ethAmount, _op.erc20Amount, _op.blockNum, _op.theta) = _queryOracle(_token1, CoFiX_OP.MINT, data);
            uint256 navps = calcNAVPerShare(_reserve0, _reserve1, _op.ethAmount, _op.erc20Amount);
            if (totalSupply == 0) {
                liquidity = calcLiquidity(amount0, navps).sub(MINIMUM_LIQUIDITY);
                _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
            } else {
                liquidity = calcLiquidity(amount0, navps);
            }
        }
        oracleFeeChange = msg.value.sub(_ethBalanceBefore.sub(address(this).balance));

        require(liquidity > 0, "CPair: SHORT_LIQUIDITY_MINTED");
        _mint(to, liquidity);

        _update(balance0, balance1);
        if (oracleFeeChange > 0) TransferHelper.safeTransferETH(msg.sender, oracleFeeChange);

        emit Mint(msg.sender, amount0, amount1);
    }

    // this low-level function should be called from a contract which performs important safety checks
    function burn(address tokenTo, address ethTo) external payable override lock returns (uint amountTokenOut, uint amountEthOut, uint oracleFeeChange) {
        address _token0 = token0;                                // gas savings
        address _token1 = token1;                                // gas savings
        uint balance0 = IERC20(_token0).balanceOf(address(this));
        uint balance1 = IERC20(_token1).balanceOf(address(this));
        uint liquidity = balanceOf[address(this)];

        uint256 _ethBalanceBefore = address(this).balance;
        // uint256 fee;
        {
            bytes memory data = abi.encode(msg.sender, liquidity);
            // query price
            OraclePrice memory _op;
            (_op.K, _op.ethAmount, _op.erc20Amount, _op.blockNum, _op.theta) = _queryOracle(_token1, CoFiX_OP.BURN, data);

            (amountTokenOut, amountEthOut) = calcOutTokenAndETHForBurn(liquidity, _op); // navps calculated
        }
        oracleFeeChange = msg.value.sub(_ethBalanceBefore.sub(address(this).balance));

        require(amountTokenOut > 0 && amountEthOut > 0, "CPair: SHORT_LIQUIDITY_BURNED");

        _burn(address(this), liquidity);
        _safeTransfer(_token1, tokenTo, amountTokenOut);
        _safeTransfer(_token0, ethTo, amountEthOut);

        // if (fee > 0) {
        //     if (ICoFiXV2Factory(factory).getTradeMiningStatus(_token1)) {
        //         // only transfer fee to protocol feeReceiver when trade mining is enabled for this trading pair
        //         _safeSendFeeForDAO(_token0, fee);
        //     } else {
        //         _safeSendFeeForLP(_token0, _token1, fee);
        //     }
        // }

        balance0 = IERC20(_token0).balanceOf(address(this));
        balance1 = IERC20(_token1).balanceOf(address(this));

        _update(balance0, balance1);
        if (oracleFeeChange > 0) TransferHelper.safeTransferETH(msg.sender, oracleFeeChange);

        emit Burn(msg.sender, _token0, amountEthOut, ethTo);
        emit Burn(msg.sender, _token1, amountTokenOut, tokenTo);
    }

    // this low-level function should be called from a contract which performs important safety checks
    function swapWithExact(address outToken, address to)
        external
        payable override lock
        returns (uint amountIn, uint amountOut, uint oracleFeeChange, uint256[5] memory tradeInfo)
    {
        // tradeInfo[0]: thetaFee, tradeInfo[1]: ethAmount, tradeInfo[2]: erc20Amount
        address _token0 = token0;
        address _token1 = token1;
        uint256 balance0 = IERC20(_token0).balanceOf(address(this));
        uint256 balance1 = IERC20(_token1).balanceOf(address(this));

        // uint256 fee;
        { // scope for ethAmount/erc20Amount/blockNum to avoid stack too deep error
            uint256 _ethBalanceBefore = address(this).balance;
            (uint112 _reserve0, uint112 _reserve1) = getReserves(); // gas savings

            // calc amountIn
            if (outToken == _token1) {
                amountIn = balance0.sub(_reserve0);
            } else if (outToken == _token0) {
                amountIn = balance1.sub(_reserve1);
            } else {
                revert("CPair: wrong outToken");
            }
            require(amountIn > 0, "CPair: wrong amountIn");
            bytes memory data = abi.encode(msg.sender, outToken, to, amountIn);
            // query price
            OraclePrice memory _op;
            (_op.K, _op.ethAmount, _op.erc20Amount, _op.blockNum, _op.theta) = _queryOracle(_token1, CoFiX_OP.SWAP_WITH_EXACT, data);
            
            if (outToken == _token1) {
                (amountOut, tradeInfo[0]) = calcOutToken1(amountIn, _op);
            } else if (outToken == _token0) {
                (amountOut, tradeInfo[0]) = calcOutToken0(amountIn, _op);
            }
            oracleFeeChange = msg.value.sub(_ethBalanceBefore.sub(address(this).balance));
            tradeInfo[1] = _op.ethAmount;
            tradeInfo[2] = _op.erc20Amount;
        }
        
        require(to != _token0 && to != _token1, "CPair: INVALID_TO");

        _safeTransfer(outToken, to, amountOut); // optimistically transfer tokens
        if (tradeInfo[0] > 0) {
            if (ICoFiXV2Factory(factory).getTradeMiningStatus(_token1)) {
                // only transfer fee to protocol feeReceiver when trade mining is enabled for this trading pair
                _safeSendFeeForDAO(_token0, tradeInfo[0]);
            } else {
                _safeSendFeeForLP(_token0, _token1, tradeInfo[0]);
                tradeInfo[0] = 0; // so router won't go into the trade mining logic (reduce one more call gas cost)
            }
        }
        balance0 = IERC20(_token0).balanceOf(address(this));
        balance1 = IERC20(_token1).balanceOf(address(this));

        _update(balance0, balance1);
        if (oracleFeeChange > 0) TransferHelper.safeTransferETH(msg.sender, oracleFeeChange);

        emit Swap(msg.sender, amountIn, amountOut, outToken, to);
    }

    // force balances to match reserves
    function skim(address to) external override lock {
        address _token0 = token0; // gas savings
        address _token1 = token1; // gas savings
        _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0));
        _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1));
    }

    // force reserves to match balances
    function sync() external override lock {
        _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)));
    }

    // calc Net Asset Value Per Share (no K)
    // use it in this contract, for optimized gas usage
    function calcNAVPerShare(uint256 balance0, uint256 balance1, uint256 ethAmount, uint256 erc20Amount) public view returns (uint256 navps) {
        uint _totalSupply = totalSupply;
        if (_totalSupply == 0) {
            navps = NAVPS_BASE;
        } else {
            /*
            NV  = \frac{E_t + U_t/P_t}{(1 + \frac{k_0}{P_t})*F_t}\\\\
                = \frac{E_t + U_t * \frac{ethAmount}{erc20Amount}}{(1 + \frac{initToken1Amount}{initToken0Amount} * \frac{ethAmount}{erc20Amount})*F_t}\\\\
                = \frac{E_t * erc20Amount + U_t * ethAmount}{(erc20Amount + \frac{initToken1Amount * ethAmount}{initToken0Amount}) * F_t}\\\\
                = \frac{E_t * erc20Amount * initToken0Amount + U_t * ethAmount * initToken0Amount}{( erc20Amount * initToken0Amount + initToken1Amount * ethAmount) * F_t} \\\\
                = \frac{balance0 * erc20Amount * initToken0Amount + balance1 * ethAmount * initToken0Amount}{(erc20Amount * initToken0Amount + initToken1Amount * ethAmount) * totalSupply}
             */
            uint256 balance0MulErc20AmountMulInitToken0Amount = balance0.mul(erc20Amount).mul(initToken0Amount);
            uint256 balance1MulEthAmountMulInitToken0Amount = balance1.mul(ethAmount).mul(initToken0Amount);
            uint256 initToken1AmountMulEthAmount = initToken1Amount.mul(ethAmount);
            uint256 initToken0AmountMulErc20Amount = erc20Amount.mul(initToken0Amount);

            navps = (balance0MulErc20AmountMulInitToken0Amount.add(balance1MulEthAmountMulInitToken0Amount))
                        .div(_totalSupply).mul(NAVPS_BASE)
                        .div(initToken1AmountMulEthAmount.add(initToken0AmountMulErc20Amount));
        }
    }

    // use it in this contract, for optimized gas usage
    function calcLiquidity(uint256 amount0, uint256 navps) public pure returns (uint256 liquidity) {
        liquidity = amount0.mul(NAVPS_BASE).div(navps);
    }

    // get Net Asset Value Per Share for mint
    // only for read, could cost more gas if use it directly in contract
    function getNAVPerShareForMint(OraclePrice memory _op) public view returns (uint256 navps) {
        return calcNAVPerShare(reserve0, reserve1, _op.ethAmount, _op.erc20Amount);
    }

    // get Net Asset Value Per Share for burn
    // only for read, could cost more gas if use it directly in contract
    function getNAVPerShareForBurn(OraclePrice memory _op) external view returns (uint256 navps) {
        return calcNAVPerShare(reserve0, reserve1, _op.ethAmount, _op.erc20Amount);
    }

    // get Net Asset Value Per Share
    // only for read, could cost more gas if use it directly in contract
    function getNAVPerShare(uint256 ethAmount, uint256 erc20Amount) external override view returns (uint256 navps) {
        return calcNAVPerShare(reserve0, reserve1, ethAmount, erc20Amount);
    }

    // get estimated liquidity amount (it represents the amount of pool tokens will be minted if someone provide liquidity to the pool)
    // only for read, could cost more gas if use it directly in contract
    function getLiquidity(uint256 amount0, OraclePrice memory _op) external view returns (uint256 liquidity) {
        uint256 navps = getNAVPerShareForMint(_op);
        return calcLiquidity(amount0, navps);
    }

    function calcOutTokenAndETHForBurn(uint256 liquidity, OraclePrice memory _op) public view returns (uint256 amountTokenOut, uint256 amountEthOut) {
        // amountEthOut = liquidity * navps * (THETA_BASE - theta) / THETA_BASE
        // amountTokenOut = liquidity * navps * (THETA_BASE - theta) * initToken1Amount / (initToken0Amount * THETA_BASE)
        uint256 navps;
        {
            navps = calcNAVPerShare(reserve0, reserve1, _op.ethAmount, _op.erc20Amount);
            uint256 amountEth = liquidity.mul(navps);

            uint256 amountEthOutLarge = amountEth.mul(THETA_BASE.sub(_op.theta));
            amountEthOut = amountEthOutLarge.div(NAVPS_BASE).div(THETA_BASE);
            amountTokenOut = amountEthOutLarge.mul(initToken1Amount).div(NAVPS_BASE).div(initToken0Amount).div(THETA_BASE);
            // amountTokenOut = amountEthOut.mul(initToken1Amount).div(initToken0Amount);
        }

        // recalc amountOut when has no enough reserve0 or reserve1 to out in initAssetRatio
        {
            if (amountEthOut > reserve0) {
                // user first, out eth as much as possibile. And may leave over a few amounts of reserve1. 
                uint256 amountEthInsufficient = amountEthOut - reserve0;
                uint256 amountTokenEquivalent = amountEthInsufficient.mul(_op.erc20Amount).div(_op.ethAmount);
                amountTokenOut = amountTokenOut.add(amountTokenEquivalent);
                if (amountTokenOut > reserve1) {
                    amountTokenOut = reserve1;
                }
                amountEthOut = reserve0;

                // amountEthOut = reserve0 - fee;    
            } else if (amountTokenOut > reserve1) {
                uint256 amountTokenInsufficient = amountTokenOut - reserve1;
                uint256 amountEthEquivalent = amountTokenInsufficient.mul(_op.ethAmount).div(_op.erc20Amount);
                amountEthOut = amountEthOut.add(amountEthEquivalent);
                if (amountEthOut > reserve0) {
                    amountEthOut = reserve0;
                }
                amountTokenOut = reserve1;
            }
        }   
    }

    // get estimated amountOut for token0 (WETH) when swapWithExact
    function calcOutToken0(uint256 amountIn, OraclePrice memory _op) public pure returns (uint256 amountOut, uint256 fee) {
        /*
        x &= (a/P_{b}^{'})*\frac{THETA_{BASE} - \theta}{THETA_{BASE}} \\\\
          &= a / (\frac{erc20Amount}{ethAmount} * \frac{(k_{BASE} + k)}{(k_{BASE})}) * \frac{THETA_{BASE} - \theta}{THETA_{BASE}} \\\\
          &= \frac{a*ethAmount*k_{BASE}}{erc20Amount*(k_{BASE} + k)} * \frac{THETA_{BASE} - \theta}{THETA_{BASE}} \\\\
          &= \frac{a*ethAmount*k_{BASE}*(THETA_{BASE} - \theta)}{erc20Amount*(k_{BASE} + k)*THETA_{BASE}} \\\\
        // amountOut = amountIn * _op.ethAmount * K_BASE * (THETA_BASE - _op.theta) / _op.erc20Amount / (K_BASE + _op.K) / THETA_BASE;
        */
        amountOut = amountIn.mul(_op.ethAmount).mul(K_BASE).mul(THETA_BASE.sub(_op.theta)).div(_op.erc20Amount).div(K_BASE.add(_op.K)).div(THETA_BASE);
        if (_op.theta != 0) {
            // fee = amountIn * _op.ethAmount * K_BASE * (_op.theta) / _op.erc20Amount / (K_BASE + _op.K) / THETA_BASE;
            fee = amountIn.mul(_op.ethAmount).mul(K_BASE).mul(_op.theta).div(_op.erc20Amount).div(K_BASE.add(_op.K)).div(THETA_BASE);
        }
        return (amountOut, fee);
    }

    // get estimated amountOut for token1 (ERC20 token) when swapWithExact
    function calcOutToken1(uint256 amountIn, OraclePrice memory _op) public pure returns (uint256 amountOut, uint256 fee) {
        /*
        y &= b*P_{s}^{'}*\frac{THETA_{BASE} - \theta}{THETA_{BASE}} \\\\
          &= b * \frac{erc20Amount}{ethAmount} * \frac{(k_{BASE} - k)}{(k_{BASE})} * \frac{THETA_{BASE} - \theta}{THETA_{BASE}} \\\\
          &= \frac{b*erc20Amount*(k_{BASE} - k)*(THETA_{BASE} - \theta)}{ethAmount*k_{BASE}*THETA_{BASE}} \\\\
        // amountOut = amountIn * _op.erc20Amount * (K_BASE - _op.K) * (THETA_BASE - _op.theta) / _op.ethAmount / K_BASE / THETA_BASE;
        */
        amountOut = amountIn.mul(_op.erc20Amount).mul(K_BASE.sub(_op.K)).mul(THETA_BASE.sub(_op.theta)).div(_op.ethAmount).div(K_BASE).div(THETA_BASE);
        if (_op.theta != 0) {
            // fee = amountIn * _op.theta / THETA_BASE;
            fee = amountIn.mul(_op.theta).div(THETA_BASE);
        }
        return (amountOut, fee);
    }

    // get estimate amountInNeeded for token0 (WETH) when swapForExact
    function calcInNeededToken0(uint256 amountOut, OraclePrice memory _op) public pure returns (uint256 amountInNeeded, uint256 fee) {
        // inverse of calcOutToken1
        // amountOut = amountIn.mul(_op.erc20Amount).mul(K_BASE.sub(_op.K)).mul(THETA_BASE.sub(_op.theta)).div(_op.ethAmount).div(K_BASE).div(THETA_BASE);
        amountInNeeded = amountOut.mul(_op.ethAmount).mul(K_BASE).mul(THETA_BASE).div(_op.erc20Amount).div(K_BASE.sub(_op.K)).div(THETA_BASE.sub(_op.theta));
        if (_op.theta != 0) {
            // fee = amountIn * _op.theta / THETA_BASE;
            fee = amountInNeeded.mul(_op.theta).div(THETA_BASE);
        }
        return (amountInNeeded, fee);
    }

    // get estimate amountInNeeded for token1 (ERC20 token) when swapForExact
    function calcInNeededToken1(uint256 amountOut, OraclePrice memory _op) public pure returns (uint256 amountInNeeded, uint256 fee) {
        // inverse of calcOutToken0
        // amountOut = amountIn.mul(_op.ethAmount).mul(K_BASE).mul(THETA_BASE.sub(_op.theta)).div(_op.erc20Amount).div(K_BASE.add(_op.K)).div(THETA_BASE);
        amountInNeeded = amountOut.mul(_op.erc20Amount).mul(K_BASE.add(_op.K)).mul(THETA_BASE).div(_op.ethAmount).div(K_BASE).div(THETA_BASE.sub(_op.theta));
        if (_op.theta != 0) {
            // fee = amountIn * _op.ethAmount * K_BASE * (_op.theta) / _op.erc20Amount / (K_BASE + _op.K) / THETA_BASE;
            fee = amountInNeeded.mul(_op.ethAmount).mul(K_BASE).mul(_op.theta).div(_op.erc20Amount).div(K_BASE.add(_op.K)).div(THETA_BASE);
        }
        return (amountInNeeded, fee);
    }

    function _queryOracle(address token, CoFiX_OP op, bytes memory data) internal returns (uint256, uint256, uint256, uint256, uint256) {
        return ICoFiXV2Controller(ICoFiXV2Factory(factory).getController()).queryOracle{value: msg.value}(token, uint8(op), data);
    }

    function _safeSendFeeForDAO(address _token0, uint256 _fee) internal {
        address feeReceiver = ICoFiXV2Factory(factory).getFeeReceiver();
        if (feeReceiver == address(0)) {
            return; // if feeReceiver not set, theta fee keeps in pair pool
        }
        uint256 bal = IWETH(_token0).balanceOf(address(this));
        if (_fee > bal) {
            _fee = bal;
        }

        IWETH(_token0).withdraw(_fee);
        if (_fee > 0) TransferHelper.safeTransferETH(feeReceiver, _fee); // transfer fee to protocol dao for redeem Cofi
        // ICoFiXV2DAO(dao).addETHReward{value: _fee}(); 
    }

    // Safe WETH transfer function, just in case not having enough WETH. LP will earn these fees.
    function _safeSendFeeForLP(address _token0, address _token1, uint256 _fee) internal {
        address feeVault = ICoFiXV2Factory(factory).getFeeVaultForLP(_token1);
        if (feeVault == address(0)) {
            return; // if fee vault not set, theta fee keeps in pair pool
        }
        _safeSendFee(_token0, feeVault, _fee); // transfer fee to protocol fee reward pool for LP
    }

    function _safeSendFee(address _token0, address _receiver, uint256 _fee) internal {
        uint256 wethBal = IERC20(_token0).balanceOf(address(this));
        if (_fee > wethBal) {
            _fee = wethBal;
        }
        if (_fee > 0) _safeTransfer(_token0, _receiver, _fee); 
    }
}

// 🦄 & CoFi Rocks

// File: contracts/interface/ICoFiXV2Controller.sol

pragma solidity 0.6.12;

interface ICoFiXV2Controller {

    event NewK(address token, uint256 K, uint256 sigma, uint256 T, uint256 ethAmount, uint256 erc20Amount, uint256 blockNum);
    event NewGovernance(address _new);
    event NewOracle(address _priceOracle);
    event NewKTable(address _kTable);
    event NewTimespan(uint256 _timeSpan);
    event NewKRefreshInterval(uint256 _interval);
    event NewKLimit(int128 maxK0);
    event NewGamma(int128 _gamma);
    event NewTheta(address token, uint32 theta);
    event NewK(address token, uint32 k);
    event NewCGamma(address token, uint32 gamma);

    function addCaller(address caller) external;

    function setCGamma(address token, uint32 gamma) external;

    function queryOracle(address token, uint8 op, bytes memory data) external payable returns (uint256 k, uint256 ethAmount, uint256 erc20Amount, uint256 blockNum, uint256 theta);

    function getKInfo(address token) external view returns (uint32 k, uint32 updatedAt, uint32 theta);

    function getLatestPriceAndAvgVola(address token) external payable returns (uint256, uint256, uint256, uint256);
}
// File: contracts/interface/ICoFiXV2Factory.sol

pragma solidity 0.6.12;

interface ICoFiXV2Factory {
    // All pairs: {ETH <-> ERC20 Token}
    event PairCreated(address indexed token, address pair, uint256);
    event NewGovernance(address _new);
    event NewController(address _new);
    event NewFeeReceiver(address _new);
    event NewFeeVaultForLP(address token, address feeVault);
    event NewVaultForLP(address _new);
    event NewVaultForTrader(address _new);
    event NewVaultForCNode(address _new);
    event NewDAO(address _new);

    /// @dev Create a new token pair for trading
    /// @param  token the address of token to trade
    /// @param  initToken0Amount the initial asset ratio (initToken0Amount:initToken1Amount)
    /// @param  initToken1Amount the initial asset ratio (initToken0Amount:initToken1Amount)
    /// @return pair the address of new token pair
    function createPair(
        address token,
	    uint256 initToken0Amount,
        uint256 initToken1Amount
        )
        external
        returns (address pair);

    function getPair(address token) external view returns (address pair);
    function allPairs(uint256) external view returns (address pair);
    function allPairsLength() external view returns (uint256);

    function getTradeMiningStatus(address token) external view returns (bool status);
    function setTradeMiningStatus(address token, bool status) external;
    function getFeeVaultForLP(address token) external view returns (address feeVault); // for LPs
    function setFeeVaultForLP(address token, address feeVault) external;

    function setGovernance(address _new) external;
    function setController(address _new) external;
    function setFeeReceiver(address _new) external;
    function setVaultForLP(address _new) external;
    function setVaultForTrader(address _new) external;
    function setVaultForCNode(address _new) external;
    function setDAO(address _new) external;
    function getController() external view returns (address controller);
    function getFeeReceiver() external view returns (address feeReceiver); // For CoFi Holders
    function getVaultForLP() external view returns (address vaultForLP);
    function getVaultForTrader() external view returns (address vaultForTrader);
    function getVaultForCNode() external view returns (address vaultForCNode);
    function getDAO() external view returns (address dao);
}

// File: contracts/CoFiXV2Factory.sol

pragma solidity 0.6.12;

// Factory of CoFiX to create new CoFiXPair contract when new pair is created, managed by governance
// Governance role of this contract should be the `Timelock` contract, which is further managed by a multisig contract
contract CoFiXV2Factory is ICoFiXV2Factory {

    string constant internal pairNamePrefix = "XToken ";
    string constant internal pairSymbolPrefix = "XT-";

    mapping(address => address) public override getPair;
    address[] public override allPairs;
    address public immutable WETH;
    address public governance;
    address public controller;
    address public feeReceiver;

    address public vaultForLP;
    address public vaultForTrader;
    address public vaultForCNode;

    address public dao;

    mapping (address => bool) public override getTradeMiningStatus; // token -> bool
    mapping (address => address) public override getFeeVaultForLP; // token -> fee vault pool

    modifier onlyGovernance() {
        require(msg.sender == governance, "CFactory: !governance");
        _;
    }

    constructor(address _WETH) public {
        governance = msg.sender;
        feeReceiver = msg.sender; // set feeReceiver to a feeReceiver contract later
        WETH = _WETH;
    }

    function allPairsLength() external override view returns (uint256) {
        return allPairs.length;
    }

    function pairCodeHash() external pure returns (bytes32) {
        return keccak256(type(CoFiXV2Pair).creationCode);
    }

    function createPair(address token, uint256 initToken0Amount, uint256 initToken1Amount) external override onlyGovernance returns (address pair) {
        require(token != address(0), 'CFactory: ZERO_ADDRESS');
        require(getPair[token] == address(0), 'CFactory: PAIR_EXISTS');
        require(initToken0Amount > 0 && initToken1Amount > 0, "CFactory: ILLEGAL_AMOUNT");

        bytes memory bytecode = type(CoFiXV2Pair).creationCode;
        bytes32 salt = keccak256(abi.encodePacked(token));
        assembly {
            pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
        }
        require(pair != address(0), "CFactory: Failed on deploy");

        getPair[token] = pair;
        allPairs.push(pair);

        uint256 pairLen = allPairs.length;
        string memory _idx = uint2str(pairLen);
        string memory _name = append(pairNamePrefix, _idx);
        string memory _symbol = append(pairSymbolPrefix, _idx);
        ICoFiXV2Pair(pair).initialize(WETH, token, _name, _symbol, initToken0Amount, initToken1Amount);

        ICoFiXV2Controller(controller).addCaller(pair);
        emit PairCreated(token, pair, pairLen);
    }

    function setGovernance(address _new) external override onlyGovernance {
        require(_new != address(0), "CFactory: zero addr");
        require(_new != governance, "CFactory: same addr");
        governance = _new;
        emit NewGovernance(_new);
    }
    
    function setController(address _new) external override onlyGovernance {
        require(_new != address(0), "CFactory: zero addr");
        require(_new != controller, "CFactory: same addr");
        controller = _new;
        emit NewController(_new);
    }

    function setFeeReceiver(address _new) external override onlyGovernance {
        require(_new != address(0), "CFactory: zero addr");
        require(_new != feeReceiver, "CFactory: same addr");
        feeReceiver = _new;
        emit NewFeeReceiver(_new);
    }

    function setFeeVaultForLP(address token, address feeVault) external override onlyGovernance {
        getFeeVaultForLP[token] = feeVault;
        emit NewFeeVaultForLP(token, feeVault);
    }

    function setVaultForLP(address _new) external override onlyGovernance {
        require(_new != address(0), "CFactory: zero addr");
        require(_new != vaultForLP, "CFactory: same addr");
        vaultForLP = _new;
        emit NewVaultForLP(_new);
    }

    function setVaultForTrader(address _new) external override onlyGovernance {
        require(_new != address(0), "CFactory: zero addr");
        require(_new != vaultForTrader, "CFactory: same addr");
        vaultForTrader = _new;
        emit NewVaultForTrader(_new);
    }

    function setVaultForCNode(address _new) external override onlyGovernance {
        require(_new != address(0), "CFactory: zero addr");
        require(_new != vaultForCNode, "CFactory: same addr");
        vaultForCNode = _new;
        emit NewVaultForCNode(_new);
    }

    function setDAO(address _new) external override onlyGovernance {
        require(_new != address(0), "CFactory: zero addr");
        require(_new != dao, "CFactory: same addr");
        dao = _new;
        emit NewDAO(_new);
    }

    function setTradeMiningStatus(address token, bool status) external override onlyGovernance {
        getTradeMiningStatus[token] = status;
    }

    function getController() external view override returns (address) {
        return controller;
    }

    function getFeeReceiver() external view override returns (address) {
        return feeReceiver;
    }

    function getVaultForLP() external view override returns (address) {
        return vaultForLP;
    }

    function getVaultForTrader() external view override returns (address) {
        return vaultForTrader;
    }

    function getVaultForCNode() external view override returns (address) {
        return vaultForCNode;
    }

    function getDAO() external view override returns (address) {
        return dao;
    }

    // internal helpers

    function append(string memory a, string memory b) internal pure returns (string memory) {
        return string(abi.encodePacked(a, b));
    }

    function uint2str(uint _i) internal pure returns (string memory) {
        if (_i == 0) {
            return "0";
        }
        uint j = _i;
        uint len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint k = len - 1;
        while (_i != 0) {
            bstr[k--] = byte(uint8(48 + _i % 10));
            _i /= 10;
        }
        return string(bstr);
    }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_WETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_new","type":"address"}],"name":"NewController","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_new","type":"address"}],"name":"NewDAO","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_new","type":"address"}],"name":"NewFeeReceiver","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"feeVault","type":"address"}],"name":"NewFeeVaultForLP","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_new","type":"address"}],"name":"NewGovernance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_new","type":"address"}],"name":"NewVaultForCNode","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_new","type":"address"}],"name":"NewVaultForLP","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_new","type":"address"}],"name":"NewVaultForTrader","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"PairCreated","type":"event"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allPairs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allPairsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"initToken0Amount","type":"uint256"},{"internalType":"uint256","name":"initToken1Amount","type":"uint256"}],"name":"createPair","outputs":[{"internalType":"address","name":"pair","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dao","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDAO","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"getFeeVaultForLP","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"getPair","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"getTradeMiningStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVaultForCNode","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVaultForLP","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVaultForTrader","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pairCodeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_new","type":"address"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_new","type":"address"}],"name":"setDAO","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_new","type":"address"}],"name":"setFeeReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"feeVault","type":"address"}],"name":"setFeeVaultForLP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_new","type":"address"}],"name":"setGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setTradeMiningStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_new","type":"address"}],"name":"setVaultForCNode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_new","type":"address"}],"name":"setVaultForLP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_new","type":"address"}],"name":"setVaultForTrader","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultForCNode","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultForLP","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultForTrader","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60a060405234801561001057600080fd5b5060405161523138038061523183398101604081905261002f91610066565b60028054336001600160a01b0319918216811790925560048054909116909117905560601b6001600160601b031916608052610094565b600060208284031215610077578081fd5b81516001600160a01b038116811461008d578182fd5b9392505050565b60805160601c61517b6100b66000398061070d5280610cda525061517b6000f3fe60806040523480156200001157600080fd5b5060043610620002085760003560e01c806392eefe9b116200011d578063cb27e2c311620000b1578063e73a914c116200007b578063e73a914c14620003e5578063e8a3539214620003fc578063efdcd9741462000406578063f77c4791146200041d5762000208565b8063cb27e2c31462000396578063d2d7f81614620003ad578063d494eded14620003b7578063d725b7d614620003ce5762000208565b8063ab033ea911620000f3578063ab033ea91462000361578063ad5c46481462000378578063b3f006741462000382578063b58aa478146200038c5762000208565b806392eefe9b1462000336578063985da726146200034d5780639aab924814620003575762000208565b8063574f2ba311620001a15780637c5f3cdf116200016b5780637c5f3cdf14620002e557806380feb39814620002fc5780638140b0041462000322578063847af19a146200032c5762000208565b8063574f2ba314620002925780635aa6e67514620002ab57806372b8cbcc14620002b55780637bae702714620002cc5762000208565b80631e3dd18b11620001e35780631e3dd18b1462000250578063284cfbe014620002675780633018205f146200027e5780634162169f14620002885762000208565b806306b580e4146200020d5780631a788a02146200022f5780631dae76911462000246575b600080fd5b6200021762000427565b6040516200022691906200145a565b60405180910390f35b6200021762000240366004620012bf565b62000436565b6200021762000451565b620002176200026136600462001392565b62000460565b62000217620002783660046200135c565b62000488565b6200021762000859565b6200021762000868565b6200029c62000877565b60405162000226919062001504565b620002176200087d565b62000217620002c6366004620012bf565b6200088c565b620002e3620002dd366004620012bf565b620008a7565b005b620002e3620002f6366004620012bf565b6200099e565b620003136200030d366004620012bf565b62000a8a565b604051620002269190620014f9565b6200021762000a9f565b6200021762000aae565b620002e362000347366004620012bf565b62000abd565b6200021762000ba9565b6200029c62000bb8565b620002e362000372366004620012bf565b62000bec565b6200021762000cd8565b6200021762000cfc565b6200021762000d0b565b620002e3620003a7366004620012e4565b62000d1a565b6200021762000dce565b620002e3620003c83660046200131d565b62000ddd565b620002e3620003df366004620012bf565b62000e53565b620002e3620003f6366004620012bf565b62000f3f565b620002176200102b565b620002e362000417366004620012bf565b6200103a565b6200021762001126565b6006546001600160a01b031681565b6000602081905290815260409020546001600160a01b031681565b6007546001600160a01b031690565b600181815481106200046e57fe5b6000918252602090912001546001600160a01b0316905081565b6002546000906001600160a01b03163314620004c15760405162461bcd60e51b8152600401620004b890620015e9565b60405180910390fd5b6001600160a01b038416620004ea5760405162461bcd60e51b8152600401620004b8906200150d565b6001600160a01b038481166000908152602081905260409020541615620005255760405162461bcd60e51b8152600401620004b8906200157b565b600083118015620005365750600082115b620005555760405162461bcd60e51b8152600401620004b89062001620565b606060405180602001620005699062001299565b6020820181038252601f19601f820116604052509050600085604051602001620005949190620013f7565b604051602081830303815290604052805190602001209050808251602084016000f592506001600160a01b038316620005e15760405162461bcd60e51b8152600401620004b890620015b2565b6001600160a01b03808716600090815260208190526040812080549286167fffffffffffffffffffffffff00000000000000000000000000000000000000009384168117909155600180548082018255928190527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6909201805490931617909155546060620006708262001135565b90506060620006b56040518060400160405280600781526020017f58546f6b656e2000000000000000000000000000000000000000000000000000815250836200126a565b90506060620006fa6040518060400160405280600381526020017f58542d0000000000000000000000000000000000000000000000000000000000815250846200126a565b9050866001600160a01b03166379c2c9547f00000000000000000000000000000000000000000000000000000000000000008c85858e8e6040518763ffffffff1660e01b8152600401620007549695949392919062001488565b600060405180830381600087803b1580156200076f57600080fd5b505af115801562000784573d6000803e3d6000fd5b50506003546040517f747293fb0000000000000000000000000000000000000000000000000000000081526001600160a01b03909116925063747293fb9150620007d3908a906004016200145a565b600060405180830381600087803b158015620007ee57600080fd5b505af115801562000803573d6000803e3d6000fd5b50505050896001600160a01b03167fc1db9ba7c4b7ce660fe8d17bbcf07167549381df2abd694a970bd1402d86d313888660405162000844929190620014e0565b60405180910390a25050505050509392505050565b6003546001600160a01b031690565b6008546001600160a01b031681565b60015490565b6002546001600160a01b031681565b600a602052600090815260409020546001600160a01b031681565b6002546001600160a01b03163314620008d45760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b038116620008fd5760405162461bcd60e51b8152600401620004b89062001657565b6005546001600160a01b03828116911614156200092e5760405162461bcd60e51b8152600401620004b89062001544565b600580547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f67dc7d9f59b39efcc9e1b3a2c2109c2b212fc362b17a6190027eb18cc3afa6e490620009939083906200145a565b60405180910390a150565b6002546001600160a01b03163314620009cb5760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b038116620009f45760405162461bcd60e51b8152600401620004b89062001657565b6006546001600160a01b038281169116141562000a255760405162461bcd60e51b8152600401620004b89062001544565b600680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f2f2656fd872771c0eeb3cd0a9ec1a2080a44a7bacbc1de33587cad3b2e34ec5090620009939083906200145a565b60096020526000908152604090205460ff1681565b6007546001600160a01b031681565b6005546001600160a01b031681565b6002546001600160a01b0316331462000aea5760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b03811662000b135760405162461bcd60e51b8152600401620004b89062001657565b6003546001600160a01b038281169116141562000b445760405162461bcd60e51b8152600401620004b89062001544565b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517fe253457d9ad994ca9682fc3bbc38c890dca73a2d5ecee3809e548bac8b00d7c690620009939083906200145a565b6008546001600160a01b031690565b60006040518060200162000bcc9062001299565b6020820181038252601f19601f8201166040525080519060200120905090565b6002546001600160a01b0316331462000c195760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b03811662000c425760405162461bcd60e51b8152600401620004b89062001657565b6002546001600160a01b038281169116141562000c735760405162461bcd60e51b8152600401620004b89062001544565b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f4f386975ea1c2f7cf1845b08bee00626fbb624ecad16254d63d9bb9ba86526de90620009939083906200145a565b7f000000000000000000000000000000000000000000000000000000000000000081565b6004546001600160a01b031681565b6006546001600160a01b031690565b6002546001600160a01b0316331462000d475760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b038281166000908152600a60205260409081902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001692841692909217909155517f360d77988e9d7232292cbbd29e6b03381c697d3dd022cbf68ce2ad4f962e13db9062000dc290849084906200146e565b60405180910390a15050565b6005546001600160a01b031690565b6002546001600160a01b0316331462000e0a5760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b0391909116600090815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b6002546001600160a01b0316331462000e805760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b03811662000ea95760405162461bcd60e51b8152600401620004b89062001657565b6007546001600160a01b038281169116141562000eda5760405162461bcd60e51b8152600401620004b89062001544565b600780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f4a43ee60176d4fc191e384a77ee14eb01d46872ac0f7a1eacc4f65d03d3b881990620009939083906200145a565b6002546001600160a01b0316331462000f6c5760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b03811662000f955760405162461bcd60e51b8152600401620004b89062001657565b6008546001600160a01b038281169116141562000fc65760405162461bcd60e51b8152600401620004b89062001544565b600880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f8a95f7dc00ff6d8cd247fa890923a32049dfe68b14abce48ea67d4d50fd774c190620009939083906200145a565b6004546001600160a01b031690565b6002546001600160a01b03163314620010675760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b038116620010905760405162461bcd60e51b8152600401620004b89062001657565b6004546001600160a01b0382811691161415620010c15760405162461bcd60e51b8152600401620004b89062001544565b600480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f010444796a5a2a97780dbda60b888795c594cc841f49c2513bb0f66258c5789290620009939083906200145a565b6003546001600160a01b031681565b60608162001178575060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015262001265565b8160005b81156200119257600101600a820491506200117c565b60608167ffffffffffffffff81118015620011ac57600080fd5b506040519080825280601f01601f191660200182016040528015620011d8576020820181803683370190505b5090507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82015b85156200125f57600a860660300160f81b828280600190039350815181106200122457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a86049550620011ff565b50925050505b919050565b606082826040516020016200128192919062001427565b60405160208183030381529060405290505b92915050565b613a8480620016c283390190565b80356001600160a01b03811681146200129357600080fd5b600060208284031215620012d1578081fd5b620012dd8383620012a7565b9392505050565b60008060408385031215620012f7578081fd5b620013038484620012a7565b9150620013148460208501620012a7565b90509250929050565b6000806040838503121562001330578182fd5b6200133c8484620012a7565b91506020830135801515811462001351578182fd5b809150509250929050565b60008060006060848603121562001371578081fd5b6200137d8585620012a7565b95602085013595506040909401359392505050565b600060208284031215620013a4578081fd5b5035919050565b60008151808452620013c58160208601602086016200168e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815260140190565b600083516200143b8184602088016200168e565b835190830190620014518183602088016200168e565b01949350505050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b60006001600160a01b03808916835280881660208401525060c06040830152620014b660c0830187620013ab565b8281036060840152620014ca8187620013ab565b6080840195909552505060a00152949350505050565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b90815260200190565b60208082526016908201527f43466163746f72793a205a45524f5f4144445245535300000000000000000000604082015260600190565b60208082526013908201527f43466163746f72793a2073616d65206164647200000000000000000000000000604082015260600190565b60208082526015908201527f43466163746f72793a20504149525f4558495354530000000000000000000000604082015260600190565b6020808252601a908201527f43466163746f72793a204661696c6564206f6e206465706c6f79000000000000604082015260600190565b60208082526015908201527f43466163746f72793a2021676f7665726e616e63650000000000000000000000604082015260600190565b60208082526018908201527f43466163746f72793a20494c4c4547414c5f414d4f554e540000000000000000604082015260600190565b60208082526013908201527f43466163746f72793a207a65726f206164647200000000000000000000000000604082015260600190565b60005b83811015620016ab57818101518382015260200162001691565b83811115620016bb576000848401525b5050505056fe60a06040526001600c553480156200001657600080fd5b50604080518082018252601081526f21b7a334ac102837b7b6102a37b5b2b760811b6020918201528151808301835260018152603160f81b9082015290514691620000cc917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f917f70f1d8d3a2b874a116643bbbdb7e2937ce56e0359f9c3070aac2ec77a8354ccc917fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6918691309101620000f5565b60408051601f198184030181529190528051602090910120600355503360601b60805262000121565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b60805160601c61392c620001586000398061148e5280611a6f5280611f0652806123b95280612a095280612bff525061392c6000f3fe6080604052600436106102d55760003560e01c806395d89b4111610179578063bc25cf77116100d6578063d385a3ad1161008a578063e5eac39011610064578063e5eac39014610731578063f22e2ae014610751578063fff6cae914610766576102dc565b8063d385a3ad146106d1578063d505accf146106f1578063dd62ed3e14610711576102dc565b8063bf36aac2116100bb578063bf36aac214610687578063c45a0155146106a7578063d21220a7146106bc576102dc565b8063bc25cf7714610667578063be5b32f8146104a4576102dc565b8063a661dbda1161012d578063aaf07e9211610112578063aaf07e921461047a578063ac931c5a14610632578063ba9a7a5614610652576102dc565b8063a661dbda146105fd578063a9059cbb14610612576102dc565b80639c673c521161015e5780639c673c52146105a55780639f44296a146105c5578063a1da4d24146105e8576102dc565b806395d89b411461057057806399f45e4814610585576102dc565b806330adf81f116102325780634f6ec2dd116101e657806379c2c954116101c057806379c2c954146105195780637ecebe001461053b5780638a2ffb961461055b576102dc565b80634f6ec2dd146104c45780635ad6bd30146104d957806370a08231146104f9576102dc565b80633298613111610217578063329861311461047a5780633644e5151461048f57806339818b66146104a4576102dc565b806330adf81f14610443578063313ce56714610458576102dc565b806318160ddd1161028957806323b872dd1161026e57806323b872dd146103e157806324334be81461040157806327fc84a314610421576102dc565b806318160ddd1461039f5780631feb1886146103c1576102dc565b8063095ea7b3116102ba578063095ea7b31461032f5780630dfe16811461035c578063156e29f61461037e576102dc565b806306fdde03146102e15780630902f1ac1461030c576102dc565b366102dc57005b600080fd5b3480156102ed57600080fd5b506102f661077b565b6040516103039190613391565b60405180910390f35b34801561031857600080fd5b50610321610827565b6040516103039291906137ce565b34801561033b57600080fd5b5061034f61034a366004613093565b610854565b604051610303919061332b565b34801561036857600080fd5b5061037161086b565b6040516103039190613277565b61039161038c3660046130be565b61087a565b6040516103039291906137ef565b3480156103ab57600080fd5b506103b4610bfe565b6040516103039190613336565b3480156103cd57600080fd5b506103916103dc366004613145565b610c04565b3480156103ed57600080fd5b5061034f6103fc366004612fde565b610e80565b34801561040d57600080fd5b506103b461041c366004613168565b610f32565b61043461042f366004612f0e565b610f70565b6040516103039392919061381c565b34801561044f57600080fd5b506103b4611345565b34801561046457600080fd5b5061046d611369565b604051610303919061387d565b34801561048657600080fd5b506103b461136e565b34801561049b57600080fd5b506103b4611376565b3480156104b057600080fd5b506103b46104bf366004613112565b61137c565b3480156104d057600080fd5b506103b46113ba565b3480156104e557600080fd5b506103916104f4366004613145565b6113c6565b34801561050557600080fd5b506103b4610514366004612ed6565b611471565b34801561052557600080fd5b50610539610534366004612f46565b611483565b005b34801561054757600080fd5b506103b4610556366004612ed6565b611547565b34801561056757600080fd5b506103b4611559565b34801561057c57600080fd5b506102f661155f565b34801561059157600080fd5b506103b46105a0366004613189565b6115d8565b3480156105b157600080fd5b506103916105c0366004613145565b61168b565b6105d86105d3366004612f0e565b61171f565b6040516103039493929190613832565b3480156105f457600080fd5b50610391611c99565b34801561060957600080fd5b506102f6611ca2565b34801561061e57600080fd5b5061034f61062d366004613093565b611cdb565b34801561063e57600080fd5b506103b461064d366004613168565b611ce8565b34801561065e57600080fd5b506103b4611d00565b34801561067357600080fd5b50610539610682366004612ed6565b611d08565b34801561069357600080fd5b506103916106a2366004613145565b611e4a565b3480156106b357600080fd5b50610371611f04565b3480156106c857600080fd5b50610371611f28565b3480156106dd57600080fd5b506103b46106ec366004613145565b611f37565b3480156106fd57600080fd5b5061053961070c36600461301e565b611f57565b34801561071d57600080fd5b506103b461072c366004612f0e565b6120c6565b34801561073d57600080fd5b5061039161074c366004613145565b6120e3565b34801561075d57600080fd5b506103b46121aa565b34801561077257600080fd5b506105396121b0565b6005805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561081f5780601f106107f45761010080835404028352916020019161081f565b820191906000526020600020905b81548152906001019060200180831161080257829003601f168201915b505050505081565b6009546dffffffffffffffffffffffffffff808216926e0100000000000000000000000000009092041690565b60006108613384846122e5565b5060015b92915050565b6007546001600160a01b031681565b600080600c546001146108a85760405162461bcd60e51b815260040161089f906133a4565b60405180910390fd5b6000600c8190556007546008546001600160a01b0391821692911690806108cd610827565b915091506000846001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016108ff9190613277565b60206040518083038186803b15801561091757600080fd5b505afa15801561092b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094f919061312d565b90506000846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161097f9190613277565b60206040518083038186803b15801561099757600080fd5b505afa1580156109ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109cf919061312d565b905060006109ed836dffffffffffffffffffffffffffff871661234d565b90506000610a0b836dffffffffffffffffffffffffffff871661234d565b9050818c11158015610a1d5750808b11155b610a395760405162461bcd60e51b815260040161089f906135f0565b5050600b548a908a90610a4d908290612375565b600a54610a5b908490612375565b14610a785760405162461bcd60e51b815260040161089f906134ee565b60004790506060338f8585604051602001610a9694939291906132b5565b6040516020818303038152906040529050610aaf612d3e565b610abb8a6001846123af565b60808601526040850152602084018190528184526060840192909252600091610afb916dffffffffffffffffffffffffffff808e1692908d1691906115d8565b905060005460001415610b3657610b20633b9aca00610b1a8884611ce8565b9061234d565b9d50610b316000633b9aca006124e9565b610b43565b610b408682611ce8565b9d505b50610b5c9150610b559050824761234d565b349061234d565b995060008b11610b7e5760405162461bcd60e51b815260040161089f9061365e565b610b888e8c6124e9565b610b928585612576565b8915610ba257610ba2338b61267c565b336001600160a01b03167f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f8484604051610bdd9291906137ef565b60405180910390a25050505050505050506001600c81905550935093915050565b60005481565b6009548151602083015160009283928392610c46926dffffffffffffffffffffffffffff808216936e01000000000000000000000000000090920416916115d8565b90506000610c548683612375565b90506000610c7d610c7687608001516305f5e10061234d90919063ffffffff16565b8390612375565b9050610c9f6305f5e100610c9983670de0b6b3a764000061270e565b9061270e565b9350610cd06305f5e100610c99600b54610c99670de0b6b3a7640000610c99600a548861237590919063ffffffff16565b6009549095506dffffffffffffffffffffffffffff168411159150610da1905057600954845160208601516dffffffffffffffffffffffffffff909216840391600091610d2291610c99908590612375565b9050610d2e8582612740565b6009549095506e01000000000000000000000000000090046dffffffffffffffffffffffffffff16851115610d85576009546e01000000000000000000000000000090046dffffffffffffffffffffffffffff1694505b50506009546dffffffffffffffffffffffffffff169150610e78565b6009546e01000000000000000000000000000090046dffffffffffffffffffffffffffff16831115610e7857600954602085015185516e0100000000000000000000000000009092046dffffffffffffffffffffffffffff16850391600091610e0f91610c99908590612375565b9050610e1b8482612740565b6009549094506dffffffffffffffffffffffffffff16841115610e4e576009546dffffffffffffffffffffffffffff1693505b50506009546e01000000000000000000000000000090046dffffffffffffffffffffffffffff1692505b509250929050565b6001600160a01b03831660009081526002602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610f1d576001600160a01b0384166000908152600260209081526040808320338452909152902054610ef8908361234d565b6001600160a01b03851660009081526002602090815260408083203384529091529020555b610f28848484612765565b5060019392505050565b600954600090610f69906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041685856115d8565b9392505050565b6000806000600c54600114610f975760405162461bcd60e51b815260040161089f906133a4565b6000600c8190556007546008546040516370a0823160e01b81526001600160a01b0392831693919092169183906370a0823190610fd8903090600401613277565b60206040518083038186803b158015610ff057600080fd5b505afa158015611004573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611028919061312d565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016110589190613277565b60206040518083038186803b15801561107057600080fd5b505afa158015611084573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a8919061312d565b30600090815260016020908152604091829020549151929350909147916060916110d69133918691016132de565b60405160208183030381529060405290506110ef612d3e565b6110fb876002846123af565b6080860152604085015260208401528252606082015261111b8482610c04565b909b5099506111319150610b559050824761234d565b96506000891180156111435750600088115b61115f5760405162461bcd60e51b815260040161089f90613627565b6111693083612809565b611174858c8b612893565b61117f868b8a612893565b6040516370a0823160e01b81526001600160a01b038716906370a08231906111ab903090600401613277565b60206040518083038186803b1580156111c357600080fd5b505afa1580156111d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111fb919061312d565b6040516370a0823160e01b81529094506001600160a01b038616906370a082319061122a903090600401613277565b60206040518083038186803b15801561124257600080fd5b505afa158015611256573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127a919061312d565b92506112868484612576565b861561129657611296338861267c565b896001600160a01b0316336001600160a01b03167f3dd1df88dc92e2788892542d81f999d720a44b4c127065d45c128f4f59fdc373888b6040516112db9291906132de565b60405180910390a38a6001600160a01b0316336001600160a01b03167f3dd1df88dc92e2788892542d81f999d720a44b4c127065d45c128f4f59fdc373878c6040516113289291906132de565b60405180910390a35050505050506001600c819055509250925092565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b6305f5e10081565b60035481565b60095481516020830151600092610865926dffffffffffffffffffffffffffff808316936e01000000000000000000000000000090930416916115d8565b670de0b6b3a764000081565b60008061143a6113e784608001516305f5e10061234d90919063ffffffff16565b610c9961140586606001516305f5e10061234d90919063ffffffff16565b610c998760200151610c996305f5e1006114346305f5e1006114348d600001518f61237590919063ffffffff16565b90612375565b9150826080015160001461146a576114676305f5e100610c9985608001518561237590919063ffffffff16565b90505b9250929050565b60016020526000908152604090205481565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146114cb5760405162461bcd60e51b815260040161089f90613695565b600780546001600160a01b038089167fffffffffffffffffffffffff00000000000000000000000000000000000000009283161790925560088054928816929091169190911790558351611526906005906020870190612d6d565b50825161153a906006906020860190612d6d565b50600a55600b5550505050565b60046020526000908152604090205481565b600b5481565b6006805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561081f5780601f106107f45761010080835404028352916020019161081f565b60008054806115f157670de0b6b3a76400009150611682565b600b54600090611605906114348987612375565b90506000611622600b54611434888a61237590919063ffffffff16565b9050600061163b87600a5461237590919063ffffffff16565b90506000611654600b548861237590919063ffffffff16565b905061167b6116638383612740565b610c99670de0b6b3a764000061143489838a8a612740565b9550505050505b50949350505050565b6000806116f26305f5e100610c996305f5e100610c998760000151610c996116c48a608001516305f5e10061234d90919063ffffffff16565b6114346116e28c606001516305f5e10061234d90919063ffffffff16565b60208d0151611434908f90612375565b9150826080015160001461146a576114676305f5e100610c9985608001518761237590919063ffffffff16565b600080600061172c612deb565b600c5460011461174e5760405162461bcd60e51b815260040161089f906133a4565b6000600c8190556007546008546040516370a0823160e01b81526001600160a01b0392831693919092169183906370a082319061178f903090600401613277565b60206040518083038186803b1580156117a757600080fd5b505afa1580156117bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117df919061312d565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161180f9190613277565b60206040518083038186803b15801561182757600080fd5b505afa15801561183b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185f919061312d565b90504760008061186d610827565b91509150856001600160a01b03168d6001600160a01b031614156118ac576118a5856dffffffffffffffffffffffffffff841661234d565b9a506118f8565b866001600160a01b03168d6001600160a01b031614156118e0576118a5846dffffffffffffffffffffffffffff831661234d565b60405162461bcd60e51b815260040161089f906135b9565b60008b116119185760405162461bcd60e51b815260040161089f90613797565b6060338e8e8e604051602001611931949392919061328b565b604051602081830303815290604052905061194a612d3e565b611956886003846123af565b608086015260408501526020840152825260608201526001600160a01b038f811690891614156119935761198a8d8261168b565b8b529b506119bc565b886001600160a01b03168f6001600160a01b031614156119bc576119b78d826120e3565b8b529b505b6119c9610b55864761234d565b815160208c8101919091529091015160408b01529950505050506001600160a01b03848116908a1614801590611a115750826001600160a01b0316896001600160a01b031614155b611a2d5760405162461bcd60e51b815260040161089f90613480565b611a388a8a89612893565b845115611b1f576040517f80feb3980000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906380feb39890611aa4908690600401613277565b60206040518083038186803b158015611abc57600080fd5b505afa158015611ad0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af491906130f2565b15611b0b578451611b06908590612a05565b611b1f565b8451611b1a9085908590612bcc565b600085525b6040516370a0823160e01b81526001600160a01b038516906370a0823190611b4b903090600401613277565b60206040518083038186803b158015611b6357600080fd5b505afa158015611b77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9b919061312d565b6040516370a0823160e01b81529092506001600160a01b038416906370a0823190611bca903090600401613277565b60206040518083038186803b158015611be257600080fd5b505afa158015611bf6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1a919061312d565b9050611c268282612576565b8515611c3657611c36338761267c565b886001600160a01b0316336001600160a01b03167f053d794b2310b8d186a24ae24a65ee066983a52a6efa6bd3df09a7601a3cb4f38a8a8e604051611c7d939291906137fd565b60405180910390a350506001600c555093969295509093509150565b600a54600b5491565b6040518060400160405280601081526020017f436f46695820506f6f6c20546f6b656e0000000000000000000000000000000081525081565b6000610861338484612765565b6000610f6982610c9985670de0b6b3a7640000612375565b633b9aca0081565b600c54600114611d2a5760405162461bcd60e51b815260040161089f906133a4565b6000600c556007546008546009546040516370a0823160e01b81526001600160a01b039384169390921691611ddf9184918691611dda916dffffffffffffffffffffffffffff9091169084906370a0823190611d8a903090600401613277565b60206040518083038186803b158015611da257600080fd5b505afa158015611db6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b1a919061312d565b612893565b611e408184611dda6009600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16856001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611d8a9190613277565b50506001600c5550565b600080611ea1611e6b84608001516305f5e10061234d90919063ffffffff16565b610c996305f5e100610c998760000151610c996305f5e1006114346116e28c606001516305f5e10061274090919063ffffffff16565b9150826080015160001461146a576114676305f5e100610c99611ed586606001516305f5e10061274090919063ffffffff16565b610c998760200151610c9989608001516114346305f5e1006114348d600001518d61237590919063ffffffff16565b7f000000000000000000000000000000000000000000000000000000000000000081565b6008546001600160a01b031681565b600080611f438361137c565b9050611f4f8482611ce8565b949350505050565b42841015611f775760405162461bcd60e51b815260040161089f90613582565b6003546001600160a01b03881660009081526004602090815260408083208054600181019091559051929392611fd8927f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9928d928d928d92918d910161333f565b60405160208183030381529060405280519060200120604051602001611fff929190613241565b60405160208183030381529060405280519060200120905060006001828686866040516000815260200160405260405161203c9493929190613373565b6020604051602081039080840390855afa15801561205e573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906120945750886001600160a01b0316816001600160a01b0316145b6120b05760405162461bcd60e51b815260040161089f906133db565b6120bb8989896122e5565b505050505050505050565b600260209081526000928352604080842090915290825290205481565b6000806121476305f5e100610c9961210c86606001516305f5e10061274090919063ffffffff16565b610c998760200151610c996121328a608001516305f5e10061234d90919063ffffffff16565b8a51611434906305f5e1009082908f90612375565b9150826080015160001461146a576114676305f5e100610c9961217b86606001516305f5e10061274090919063ffffffff16565b610c998760200151610c9989608001516114346305f5e1006114348d600001518f61237590919063ffffffff16565b600a5481565b600c546001146121d25760405162461bcd60e51b815260040161089f906133a4565b6000600c556007546040516370a0823160e01b81526122de916001600160a01b0316906370a0823190612209903090600401613277565b60206040518083038186803b15801561222157600080fd5b505afa158015612235573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612259919061312d565b6008546040516370a0823160e01b81526001600160a01b03909116906370a0823190612289903090600401613277565b60206040518083038186803b1580156122a157600080fd5b505afa1580156122b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122d9919061312d565b612576565b6001600c55565b6001600160a01b0380841660008181526002602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590612340908590613336565b60405180910390a3505050565b60008282111561236f5760405162461bcd60e51b815260040161089f90613449565b50900390565b60008261238457506000610865565b8282028284828161239157fe5b0414610f695760405162461bcd60e51b815260040161089f90613525565b60008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633018205f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561241057600080fd5b505afa158015612424573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124489190612ef2565b6001600160a01b0316638dba9329348a8a600481111561246457fe5b8a6040518563ffffffff1660e01b8152600401612483939291906132f7565b60a0604051808303818588803b15801561249c57600080fd5b505af11580156124b0573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906124d591906131ba565b939c929b5090995097509095509350505050565b6000546124f69082612740565b60009081556001600160a01b03831681526001602052604090205461251b9082612740565b6001600160a01b0383166000818152600160205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061256a908590613336565b60405180910390a35050565b6dffffffffffffffffffffffffffff82118015906125a257506dffffffffffffffffffffffffffff8111155b6125be5760405162461bcd60e51b815260040161089f90613760565b600980547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff848116919091177fffffffff0000000000000000000000000000ffffffffffffffffffffffffffff166e010000000000000000000000000000848316810291909117928390556040517f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad193612670938181169390910416906137ce565b60405180910390a15050565b604080516000808252602082019092526001600160a01b0384169083906040516126a69190613225565b60006040518083038185875af1925050503d80600081146126e3576040519150601f19603f3d011682016040523d82523d6000602084013e6126e8565b606091505b50509050806127095760405162461bcd60e51b815260040161089f906136cc565b505050565b600080821161272f5760405162461bcd60e51b815260040161089f906134b7565b81838161273857fe5b049392505050565b600082820183811015610f695760405162461bcd60e51b815260040161089f90613412565b6001600160a01b038316600090815260016020526040902054612788908261234d565b6001600160a01b0380851660009081526001602052604080822093909355908416815220546127b79082612740565b6001600160a01b0380841660008181526001602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612340908590613336565b6001600160a01b03821660009081526001602052604090205461282c908261234d565b6001600160a01b03831660009081526001602052604081209190915554612853908261234d565b60009081556040516001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061256a908590613336565b604080518082018252601981527f7472616e7366657228616464726573732c75696e743235362900000000000000602090910152516000906060906001600160a01b038616907fa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b9061290b90879087906024016132de565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516129769190613225565b6000604051808303816000865af19150503d80600081146129b3576040519150601f19603f3d011682016040523d82523d6000602084013e6129b8565b606091505b50915091508180156129e25750805115806129e25750808060200190518101906129e291906130f2565b6129fe5760405162461bcd60e51b815260040161089f90613729565b5050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e8a353926040518163ffffffff1660e01b815260040160206040518083038186803b158015612a6057600080fd5b505afa158015612a74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a989190612ef2565b90506001600160a01b038116612aae5750612bc8565b6040516370a0823160e01b81526000906001600160a01b038516906370a0823190612add903090600401613277565b60206040518083038186803b158015612af557600080fd5b505afa158015612b09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b2d919061312d565b905080831115612b3b578092505b6040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526001600160a01b03851690632e1a7d4d90612b80908690600401613336565b600060405180830381600087803b158015612b9a57600080fd5b505af1158015612bae573d6000803e3d6000fd5b505050506000831115612bc557612bc5828461267c565b50505b5050565b6040517f72b8cbcc0000000000000000000000000000000000000000000000000000000081526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906372b8cbcc90612c34908690600401613277565b60206040518083038186803b158015612c4c57600080fd5b505afa158015612c60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c849190612ef2565b90506001600160a01b038116612c9a5750612709565b612bc58482846040516370a0823160e01b81526000906001600160a01b038516906370a0823190612ccf903090600401613277565b60206040518083038186803b158015612ce757600080fd5b505afa158015612cfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d1f919061312d565b905080821115612d2d578091505b8115612bc557612bc5848484612893565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10612dae57805160ff1916838001178555612ddb565b82800160010185558215612ddb579182015b82811115612ddb578251825591602001919060010190612dc0565b50612de7929150612e09565b5090565b6040518060a001604052806005906020820280368337509192915050565b5b80821115612de75760008155600101612e0a565b600082601f830112612e2e578081fd5b813567ffffffffffffffff811115612e44578182fd5b612e576020601f19601f8401160161388b565b9150808252836020828501011115612e6e57600080fd5b8060208401602084013760009082016020015292915050565b600060a08284031215612e98578081fd5b612ea260a061388b565b9050813581526020820135602082015260408201356040820152606082013560608201526080820135608082015292915050565b600060208284031215612ee7578081fd5b8135610f69816138de565b600060208284031215612f03578081fd5b8151610f69816138de565b60008060408385031215612f20578081fd5b8235612f2b816138de565b91506020830135612f3b816138de565b809150509250929050565b60008060008060008060c08789031215612f5e578182fd5b8635612f69816138de565b95506020870135612f79816138de565b9450604087013567ffffffffffffffff80821115612f95578384fd5b612fa18a838b01612e1e565b95506060890135915080821115612fb6578384fd5b50612fc389828a01612e1e565b9350506080870135915060a087013590509295509295509295565b600080600060608486031215612ff2578283fd5b8335612ffd816138de565b9250602084013561300d816138de565b929592945050506040919091013590565b600080600080600080600060e0888a031215613038578081fd5b8735613043816138de565b96506020880135613053816138de565b95506040880135945060608801359350608088013560ff81168114613076578182fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156130a5578182fd5b82356130b0816138de565b946020939093013593505050565b6000806000606084860312156130d2578283fd5b83356130dd816138de565b95602085013595506040909401359392505050565b600060208284031215613103578081fd5b81518015158114610f69578182fd5b600060a08284031215613123578081fd5b610f698383612e87565b60006020828403121561313e578081fd5b5051919050565b60008060c08385031215613157578182fd5b823591506114678460208501612e87565b6000806040838503121561317a578182fd5b50508035926020909101359150565b6000806000806080858703121561319e578182fd5b5050823594602084013594506040840135936060013592509050565b600080600080600060a086880312156131d1578283fd5b5050835160208501516040860151606087015160809097015192989197509594509092509050565b600081518084526132118160208601602086016138b2565b601f01601f19169290920160200192915050565b600082516132378184602087016138b2565b9190910192915050565b7f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6001600160a01b03929092168252602082015260400190565b60006001600160a01b038516825260ff841660208301526060604083015261332260608301846131f9565b95945050505050565b901515815260200190565b90815260200190565b9586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b93845260ff9290921660208401526040830152606082015260800190565b600060208252610f6960208301846131f9565b6020808252600d908201527f43506169723a204c4f434b454400000000000000000000000000000000000000604082015260600190565b60208082526019908201527f4345524332303a20494e56414c49445f5349474e415455524500000000000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b60208082526011908201527f43506169723a20494e56414c49445f544f000000000000000000000000000000604082015260600190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b6020808252601a908201527f43506169723a20696e76616c696420617373657420726174696f000000000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60408201527f7700000000000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252600f908201527f4345524332303a20455850495245440000000000000000000000000000000000604082015260600190565b60208082526015908201527f43506169723a2077726f6e67206f7574546f6b656e0000000000000000000000604082015260600190565b60208082526016908201527f43506169723a20696c6c6567616c20616d6d6f756e7400000000000000000000604082015260600190565b6020808252601d908201527f43506169723a2053484f52545f4c49515549444954595f4255524e4544000000604082015260600190565b6020808252601d908201527f43506169723a2053484f52545f4c49515549444954595f4d494e544544000000604082015260600190565b60208082526010908201527f43506169723a20464f5242494444454e00000000000000000000000000000000604082015260600190565b60208082526023908201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960408201527f4c45440000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526016908201527f43506169723a205452414e534645525f4641494c454400000000000000000000604082015260600190565b6020808252600f908201527f43506169723a204f564552464c4f570000000000000000000000000000000000604082015260600190565b60208082526015908201527f43506169723a2077726f6e6720616d6f756e74496e0000000000000000000000604082015260600190565b6dffffffffffffffffffffffffffff92831681529116602082015260400190565b918252602082015260400190565b92835260208301919091526001600160a01b0316604082015260600190565b9283526020830191909152604082015260600190565b60006101008201905085825260208581840152846040840152606083018460005b600581101561387057815183529183019190830190600101613853565b5050505095945050505050565b60ff91909116815260200190565b60405181810167ffffffffffffffff811182821017156138aa57600080fd5b604052919050565b60005b838110156138cd5781810151838201526020016138b5565b83811115612bc55750506000910152565b6001600160a01b03811681146138f357600080fd5b5056fea264697066735822122075fd8b231a5e9a3ccabafbc24c4617be2296d370b66ce185fd035003fd69a2ba64736f6c634300060c0033a264697066735822122022300740a0ad249d4feb2a90147dc2d57d3ff358566d6c43f8ee49255b79d39364736f6c634300060c0033000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

Deployed Bytecode

0x60806040523480156200001157600080fd5b5060043610620002085760003560e01c806392eefe9b116200011d578063cb27e2c311620000b1578063e73a914c116200007b578063e73a914c14620003e5578063e8a3539214620003fc578063efdcd9741462000406578063f77c4791146200041d5762000208565b8063cb27e2c31462000396578063d2d7f81614620003ad578063d494eded14620003b7578063d725b7d614620003ce5762000208565b8063ab033ea911620000f3578063ab033ea91462000361578063ad5c46481462000378578063b3f006741462000382578063b58aa478146200038c5762000208565b806392eefe9b1462000336578063985da726146200034d5780639aab924814620003575762000208565b8063574f2ba311620001a15780637c5f3cdf116200016b5780637c5f3cdf14620002e557806380feb39814620002fc5780638140b0041462000322578063847af19a146200032c5762000208565b8063574f2ba314620002925780635aa6e67514620002ab57806372b8cbcc14620002b55780637bae702714620002cc5762000208565b80631e3dd18b11620001e35780631e3dd18b1462000250578063284cfbe014620002675780633018205f146200027e5780634162169f14620002885762000208565b806306b580e4146200020d5780631a788a02146200022f5780631dae76911462000246575b600080fd5b6200021762000427565b6040516200022691906200145a565b60405180910390f35b6200021762000240366004620012bf565b62000436565b6200021762000451565b620002176200026136600462001392565b62000460565b62000217620002783660046200135c565b62000488565b6200021762000859565b6200021762000868565b6200029c62000877565b60405162000226919062001504565b620002176200087d565b62000217620002c6366004620012bf565b6200088c565b620002e3620002dd366004620012bf565b620008a7565b005b620002e3620002f6366004620012bf565b6200099e565b620003136200030d366004620012bf565b62000a8a565b604051620002269190620014f9565b6200021762000a9f565b6200021762000aae565b620002e362000347366004620012bf565b62000abd565b6200021762000ba9565b6200029c62000bb8565b620002e362000372366004620012bf565b62000bec565b6200021762000cd8565b6200021762000cfc565b6200021762000d0b565b620002e3620003a7366004620012e4565b62000d1a565b6200021762000dce565b620002e3620003c83660046200131d565b62000ddd565b620002e3620003df366004620012bf565b62000e53565b620002e3620003f6366004620012bf565b62000f3f565b620002176200102b565b620002e362000417366004620012bf565b6200103a565b6200021762001126565b6006546001600160a01b031681565b6000602081905290815260409020546001600160a01b031681565b6007546001600160a01b031690565b600181815481106200046e57fe5b6000918252602090912001546001600160a01b0316905081565b6002546000906001600160a01b03163314620004c15760405162461bcd60e51b8152600401620004b890620015e9565b60405180910390fd5b6001600160a01b038416620004ea5760405162461bcd60e51b8152600401620004b8906200150d565b6001600160a01b038481166000908152602081905260409020541615620005255760405162461bcd60e51b8152600401620004b8906200157b565b600083118015620005365750600082115b620005555760405162461bcd60e51b8152600401620004b89062001620565b606060405180602001620005699062001299565b6020820181038252601f19601f820116604052509050600085604051602001620005949190620013f7565b604051602081830303815290604052805190602001209050808251602084016000f592506001600160a01b038316620005e15760405162461bcd60e51b8152600401620004b890620015b2565b6001600160a01b03808716600090815260208190526040812080549286167fffffffffffffffffffffffff00000000000000000000000000000000000000009384168117909155600180548082018255928190527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6909201805490931617909155546060620006708262001135565b90506060620006b56040518060400160405280600781526020017f58546f6b656e2000000000000000000000000000000000000000000000000000815250836200126a565b90506060620006fa6040518060400160405280600381526020017f58542d0000000000000000000000000000000000000000000000000000000000815250846200126a565b9050866001600160a01b03166379c2c9547f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28c85858e8e6040518763ffffffff1660e01b8152600401620007549695949392919062001488565b600060405180830381600087803b1580156200076f57600080fd5b505af115801562000784573d6000803e3d6000fd5b50506003546040517f747293fb0000000000000000000000000000000000000000000000000000000081526001600160a01b03909116925063747293fb9150620007d3908a906004016200145a565b600060405180830381600087803b158015620007ee57600080fd5b505af115801562000803573d6000803e3d6000fd5b50505050896001600160a01b03167fc1db9ba7c4b7ce660fe8d17bbcf07167549381df2abd694a970bd1402d86d313888660405162000844929190620014e0565b60405180910390a25050505050509392505050565b6003546001600160a01b031690565b6008546001600160a01b031681565b60015490565b6002546001600160a01b031681565b600a602052600090815260409020546001600160a01b031681565b6002546001600160a01b03163314620008d45760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b038116620008fd5760405162461bcd60e51b8152600401620004b89062001657565b6005546001600160a01b03828116911614156200092e5760405162461bcd60e51b8152600401620004b89062001544565b600580547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f67dc7d9f59b39efcc9e1b3a2c2109c2b212fc362b17a6190027eb18cc3afa6e490620009939083906200145a565b60405180910390a150565b6002546001600160a01b03163314620009cb5760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b038116620009f45760405162461bcd60e51b8152600401620004b89062001657565b6006546001600160a01b038281169116141562000a255760405162461bcd60e51b8152600401620004b89062001544565b600680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f2f2656fd872771c0eeb3cd0a9ec1a2080a44a7bacbc1de33587cad3b2e34ec5090620009939083906200145a565b60096020526000908152604090205460ff1681565b6007546001600160a01b031681565b6005546001600160a01b031681565b6002546001600160a01b0316331462000aea5760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b03811662000b135760405162461bcd60e51b8152600401620004b89062001657565b6003546001600160a01b038281169116141562000b445760405162461bcd60e51b8152600401620004b89062001544565b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517fe253457d9ad994ca9682fc3bbc38c890dca73a2d5ecee3809e548bac8b00d7c690620009939083906200145a565b6008546001600160a01b031690565b60006040518060200162000bcc9062001299565b6020820181038252601f19601f8201166040525080519060200120905090565b6002546001600160a01b0316331462000c195760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b03811662000c425760405162461bcd60e51b8152600401620004b89062001657565b6002546001600160a01b038281169116141562000c735760405162461bcd60e51b8152600401620004b89062001544565b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f4f386975ea1c2f7cf1845b08bee00626fbb624ecad16254d63d9bb9ba86526de90620009939083906200145a565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6004546001600160a01b031681565b6006546001600160a01b031690565b6002546001600160a01b0316331462000d475760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b038281166000908152600a60205260409081902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001692841692909217909155517f360d77988e9d7232292cbbd29e6b03381c697d3dd022cbf68ce2ad4f962e13db9062000dc290849084906200146e565b60405180910390a15050565b6005546001600160a01b031690565b6002546001600160a01b0316331462000e0a5760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b0391909116600090815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b6002546001600160a01b0316331462000e805760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b03811662000ea95760405162461bcd60e51b8152600401620004b89062001657565b6007546001600160a01b038281169116141562000eda5760405162461bcd60e51b8152600401620004b89062001544565b600780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f4a43ee60176d4fc191e384a77ee14eb01d46872ac0f7a1eacc4f65d03d3b881990620009939083906200145a565b6002546001600160a01b0316331462000f6c5760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b03811662000f955760405162461bcd60e51b8152600401620004b89062001657565b6008546001600160a01b038281169116141562000fc65760405162461bcd60e51b8152600401620004b89062001544565b600880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f8a95f7dc00ff6d8cd247fa890923a32049dfe68b14abce48ea67d4d50fd774c190620009939083906200145a565b6004546001600160a01b031690565b6002546001600160a01b03163314620010675760405162461bcd60e51b8152600401620004b890620015e9565b6001600160a01b038116620010905760405162461bcd60e51b8152600401620004b89062001657565b6004546001600160a01b0382811691161415620010c15760405162461bcd60e51b8152600401620004b89062001544565b600480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f010444796a5a2a97780dbda60b888795c594cc841f49c2513bb0f66258c5789290620009939083906200145a565b6003546001600160a01b031681565b60608162001178575060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015262001265565b8160005b81156200119257600101600a820491506200117c565b60608167ffffffffffffffff81118015620011ac57600080fd5b506040519080825280601f01601f191660200182016040528015620011d8576020820181803683370190505b5090507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82015b85156200125f57600a860660300160f81b828280600190039350815181106200122457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a86049550620011ff565b50925050505b919050565b606082826040516020016200128192919062001427565b60405160208183030381529060405290505b92915050565b613a8480620016c283390190565b80356001600160a01b03811681146200129357600080fd5b600060208284031215620012d1578081fd5b620012dd8383620012a7565b9392505050565b60008060408385031215620012f7578081fd5b620013038484620012a7565b9150620013148460208501620012a7565b90509250929050565b6000806040838503121562001330578182fd5b6200133c8484620012a7565b91506020830135801515811462001351578182fd5b809150509250929050565b60008060006060848603121562001371578081fd5b6200137d8585620012a7565b95602085013595506040909401359392505050565b600060208284031215620013a4578081fd5b5035919050565b60008151808452620013c58160208601602086016200168e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815260140190565b600083516200143b8184602088016200168e565b835190830190620014518183602088016200168e565b01949350505050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b60006001600160a01b03808916835280881660208401525060c06040830152620014b660c0830187620013ab565b8281036060840152620014ca8187620013ab565b6080840195909552505060a00152949350505050565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b90815260200190565b60208082526016908201527f43466163746f72793a205a45524f5f4144445245535300000000000000000000604082015260600190565b60208082526013908201527f43466163746f72793a2073616d65206164647200000000000000000000000000604082015260600190565b60208082526015908201527f43466163746f72793a20504149525f4558495354530000000000000000000000604082015260600190565b6020808252601a908201527f43466163746f72793a204661696c6564206f6e206465706c6f79000000000000604082015260600190565b60208082526015908201527f43466163746f72793a2021676f7665726e616e63650000000000000000000000604082015260600190565b60208082526018908201527f43466163746f72793a20494c4c4547414c5f414d4f554e540000000000000000604082015260600190565b60208082526013908201527f43466163746f72793a207a65726f206164647200000000000000000000000000604082015260600190565b60005b83811015620016ab57818101518382015260200162001691565b83811115620016bb576000848401525b5050505056fe60a06040526001600c553480156200001657600080fd5b50604080518082018252601081526f21b7a334ac102837b7b6102a37b5b2b760811b6020918201528151808301835260018152603160f81b9082015290514691620000cc917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f917f70f1d8d3a2b874a116643bbbdb7e2937ce56e0359f9c3070aac2ec77a8354ccc917fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6918691309101620000f5565b60408051601f198184030181529190528051602090910120600355503360601b60805262000121565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b60805160601c61392c620001586000398061148e5280611a6f5280611f0652806123b95280612a095280612bff525061392c6000f3fe6080604052600436106102d55760003560e01c806395d89b4111610179578063bc25cf77116100d6578063d385a3ad1161008a578063e5eac39011610064578063e5eac39014610731578063f22e2ae014610751578063fff6cae914610766576102dc565b8063d385a3ad146106d1578063d505accf146106f1578063dd62ed3e14610711576102dc565b8063bf36aac2116100bb578063bf36aac214610687578063c45a0155146106a7578063d21220a7146106bc576102dc565b8063bc25cf7714610667578063be5b32f8146104a4576102dc565b8063a661dbda1161012d578063aaf07e9211610112578063aaf07e921461047a578063ac931c5a14610632578063ba9a7a5614610652576102dc565b8063a661dbda146105fd578063a9059cbb14610612576102dc565b80639c673c521161015e5780639c673c52146105a55780639f44296a146105c5578063a1da4d24146105e8576102dc565b806395d89b411461057057806399f45e4814610585576102dc565b806330adf81f116102325780634f6ec2dd116101e657806379c2c954116101c057806379c2c954146105195780637ecebe001461053b5780638a2ffb961461055b576102dc565b80634f6ec2dd146104c45780635ad6bd30146104d957806370a08231146104f9576102dc565b80633298613111610217578063329861311461047a5780633644e5151461048f57806339818b66146104a4576102dc565b806330adf81f14610443578063313ce56714610458576102dc565b806318160ddd1161028957806323b872dd1161026e57806323b872dd146103e157806324334be81461040157806327fc84a314610421576102dc565b806318160ddd1461039f5780631feb1886146103c1576102dc565b8063095ea7b3116102ba578063095ea7b31461032f5780630dfe16811461035c578063156e29f61461037e576102dc565b806306fdde03146102e15780630902f1ac1461030c576102dc565b366102dc57005b600080fd5b3480156102ed57600080fd5b506102f661077b565b6040516103039190613391565b60405180910390f35b34801561031857600080fd5b50610321610827565b6040516103039291906137ce565b34801561033b57600080fd5b5061034f61034a366004613093565b610854565b604051610303919061332b565b34801561036857600080fd5b5061037161086b565b6040516103039190613277565b61039161038c3660046130be565b61087a565b6040516103039291906137ef565b3480156103ab57600080fd5b506103b4610bfe565b6040516103039190613336565b3480156103cd57600080fd5b506103916103dc366004613145565b610c04565b3480156103ed57600080fd5b5061034f6103fc366004612fde565b610e80565b34801561040d57600080fd5b506103b461041c366004613168565b610f32565b61043461042f366004612f0e565b610f70565b6040516103039392919061381c565b34801561044f57600080fd5b506103b4611345565b34801561046457600080fd5b5061046d611369565b604051610303919061387d565b34801561048657600080fd5b506103b461136e565b34801561049b57600080fd5b506103b4611376565b3480156104b057600080fd5b506103b46104bf366004613112565b61137c565b3480156104d057600080fd5b506103b46113ba565b3480156104e557600080fd5b506103916104f4366004613145565b6113c6565b34801561050557600080fd5b506103b4610514366004612ed6565b611471565b34801561052557600080fd5b50610539610534366004612f46565b611483565b005b34801561054757600080fd5b506103b4610556366004612ed6565b611547565b34801561056757600080fd5b506103b4611559565b34801561057c57600080fd5b506102f661155f565b34801561059157600080fd5b506103b46105a0366004613189565b6115d8565b3480156105b157600080fd5b506103916105c0366004613145565b61168b565b6105d86105d3366004612f0e565b61171f565b6040516103039493929190613832565b3480156105f457600080fd5b50610391611c99565b34801561060957600080fd5b506102f6611ca2565b34801561061e57600080fd5b5061034f61062d366004613093565b611cdb565b34801561063e57600080fd5b506103b461064d366004613168565b611ce8565b34801561065e57600080fd5b506103b4611d00565b34801561067357600080fd5b50610539610682366004612ed6565b611d08565b34801561069357600080fd5b506103916106a2366004613145565b611e4a565b3480156106b357600080fd5b50610371611f04565b3480156106c857600080fd5b50610371611f28565b3480156106dd57600080fd5b506103b46106ec366004613145565b611f37565b3480156106fd57600080fd5b5061053961070c36600461301e565b611f57565b34801561071d57600080fd5b506103b461072c366004612f0e565b6120c6565b34801561073d57600080fd5b5061039161074c366004613145565b6120e3565b34801561075d57600080fd5b506103b46121aa565b34801561077257600080fd5b506105396121b0565b6005805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561081f5780601f106107f45761010080835404028352916020019161081f565b820191906000526020600020905b81548152906001019060200180831161080257829003601f168201915b505050505081565b6009546dffffffffffffffffffffffffffff808216926e0100000000000000000000000000009092041690565b60006108613384846122e5565b5060015b92915050565b6007546001600160a01b031681565b600080600c546001146108a85760405162461bcd60e51b815260040161089f906133a4565b60405180910390fd5b6000600c8190556007546008546001600160a01b0391821692911690806108cd610827565b915091506000846001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016108ff9190613277565b60206040518083038186803b15801561091757600080fd5b505afa15801561092b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094f919061312d565b90506000846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161097f9190613277565b60206040518083038186803b15801561099757600080fd5b505afa1580156109ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109cf919061312d565b905060006109ed836dffffffffffffffffffffffffffff871661234d565b90506000610a0b836dffffffffffffffffffffffffffff871661234d565b9050818c11158015610a1d5750808b11155b610a395760405162461bcd60e51b815260040161089f906135f0565b5050600b548a908a90610a4d908290612375565b600a54610a5b908490612375565b14610a785760405162461bcd60e51b815260040161089f906134ee565b60004790506060338f8585604051602001610a9694939291906132b5565b6040516020818303038152906040529050610aaf612d3e565b610abb8a6001846123af565b60808601526040850152602084018190528184526060840192909252600091610afb916dffffffffffffffffffffffffffff808e1692908d1691906115d8565b905060005460001415610b3657610b20633b9aca00610b1a8884611ce8565b9061234d565b9d50610b316000633b9aca006124e9565b610b43565b610b408682611ce8565b9d505b50610b5c9150610b559050824761234d565b349061234d565b995060008b11610b7e5760405162461bcd60e51b815260040161089f9061365e565b610b888e8c6124e9565b610b928585612576565b8915610ba257610ba2338b61267c565b336001600160a01b03167f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f8484604051610bdd9291906137ef565b60405180910390a25050505050505050506001600c81905550935093915050565b60005481565b6009548151602083015160009283928392610c46926dffffffffffffffffffffffffffff808216936e01000000000000000000000000000090920416916115d8565b90506000610c548683612375565b90506000610c7d610c7687608001516305f5e10061234d90919063ffffffff16565b8390612375565b9050610c9f6305f5e100610c9983670de0b6b3a764000061270e565b9061270e565b9350610cd06305f5e100610c99600b54610c99670de0b6b3a7640000610c99600a548861237590919063ffffffff16565b6009549095506dffffffffffffffffffffffffffff168411159150610da1905057600954845160208601516dffffffffffffffffffffffffffff909216840391600091610d2291610c99908590612375565b9050610d2e8582612740565b6009549095506e01000000000000000000000000000090046dffffffffffffffffffffffffffff16851115610d85576009546e01000000000000000000000000000090046dffffffffffffffffffffffffffff1694505b50506009546dffffffffffffffffffffffffffff169150610e78565b6009546e01000000000000000000000000000090046dffffffffffffffffffffffffffff16831115610e7857600954602085015185516e0100000000000000000000000000009092046dffffffffffffffffffffffffffff16850391600091610e0f91610c99908590612375565b9050610e1b8482612740565b6009549094506dffffffffffffffffffffffffffff16841115610e4e576009546dffffffffffffffffffffffffffff1693505b50506009546e01000000000000000000000000000090046dffffffffffffffffffffffffffff1692505b509250929050565b6001600160a01b03831660009081526002602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610f1d576001600160a01b0384166000908152600260209081526040808320338452909152902054610ef8908361234d565b6001600160a01b03851660009081526002602090815260408083203384529091529020555b610f28848484612765565b5060019392505050565b600954600090610f69906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041685856115d8565b9392505050565b6000806000600c54600114610f975760405162461bcd60e51b815260040161089f906133a4565b6000600c8190556007546008546040516370a0823160e01b81526001600160a01b0392831693919092169183906370a0823190610fd8903090600401613277565b60206040518083038186803b158015610ff057600080fd5b505afa158015611004573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611028919061312d565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016110589190613277565b60206040518083038186803b15801561107057600080fd5b505afa158015611084573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a8919061312d565b30600090815260016020908152604091829020549151929350909147916060916110d69133918691016132de565b60405160208183030381529060405290506110ef612d3e565b6110fb876002846123af565b6080860152604085015260208401528252606082015261111b8482610c04565b909b5099506111319150610b559050824761234d565b96506000891180156111435750600088115b61115f5760405162461bcd60e51b815260040161089f90613627565b6111693083612809565b611174858c8b612893565b61117f868b8a612893565b6040516370a0823160e01b81526001600160a01b038716906370a08231906111ab903090600401613277565b60206040518083038186803b1580156111c357600080fd5b505afa1580156111d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111fb919061312d565b6040516370a0823160e01b81529094506001600160a01b038616906370a082319061122a903090600401613277565b60206040518083038186803b15801561124257600080fd5b505afa158015611256573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127a919061312d565b92506112868484612576565b861561129657611296338861267c565b896001600160a01b0316336001600160a01b03167f3dd1df88dc92e2788892542d81f999d720a44b4c127065d45c128f4f59fdc373888b6040516112db9291906132de565b60405180910390a38a6001600160a01b0316336001600160a01b03167f3dd1df88dc92e2788892542d81f999d720a44b4c127065d45c128f4f59fdc373878c6040516113289291906132de565b60405180910390a35050505050506001600c819055509250925092565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b6305f5e10081565b60035481565b60095481516020830151600092610865926dffffffffffffffffffffffffffff808316936e01000000000000000000000000000090930416916115d8565b670de0b6b3a764000081565b60008061143a6113e784608001516305f5e10061234d90919063ffffffff16565b610c9961140586606001516305f5e10061234d90919063ffffffff16565b610c998760200151610c996305f5e1006114346305f5e1006114348d600001518f61237590919063ffffffff16565b90612375565b9150826080015160001461146a576114676305f5e100610c9985608001518561237590919063ffffffff16565b90505b9250929050565b60016020526000908152604090205481565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146114cb5760405162461bcd60e51b815260040161089f90613695565b600780546001600160a01b038089167fffffffffffffffffffffffff00000000000000000000000000000000000000009283161790925560088054928816929091169190911790558351611526906005906020870190612d6d565b50825161153a906006906020860190612d6d565b50600a55600b5550505050565b60046020526000908152604090205481565b600b5481565b6006805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561081f5780601f106107f45761010080835404028352916020019161081f565b60008054806115f157670de0b6b3a76400009150611682565b600b54600090611605906114348987612375565b90506000611622600b54611434888a61237590919063ffffffff16565b9050600061163b87600a5461237590919063ffffffff16565b90506000611654600b548861237590919063ffffffff16565b905061167b6116638383612740565b610c99670de0b6b3a764000061143489838a8a612740565b9550505050505b50949350505050565b6000806116f26305f5e100610c996305f5e100610c998760000151610c996116c48a608001516305f5e10061234d90919063ffffffff16565b6114346116e28c606001516305f5e10061234d90919063ffffffff16565b60208d0151611434908f90612375565b9150826080015160001461146a576114676305f5e100610c9985608001518761237590919063ffffffff16565b600080600061172c612deb565b600c5460011461174e5760405162461bcd60e51b815260040161089f906133a4565b6000600c8190556007546008546040516370a0823160e01b81526001600160a01b0392831693919092169183906370a082319061178f903090600401613277565b60206040518083038186803b1580156117a757600080fd5b505afa1580156117bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117df919061312d565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161180f9190613277565b60206040518083038186803b15801561182757600080fd5b505afa15801561183b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185f919061312d565b90504760008061186d610827565b91509150856001600160a01b03168d6001600160a01b031614156118ac576118a5856dffffffffffffffffffffffffffff841661234d565b9a506118f8565b866001600160a01b03168d6001600160a01b031614156118e0576118a5846dffffffffffffffffffffffffffff831661234d565b60405162461bcd60e51b815260040161089f906135b9565b60008b116119185760405162461bcd60e51b815260040161089f90613797565b6060338e8e8e604051602001611931949392919061328b565b604051602081830303815290604052905061194a612d3e565b611956886003846123af565b608086015260408501526020840152825260608201526001600160a01b038f811690891614156119935761198a8d8261168b565b8b529b506119bc565b886001600160a01b03168f6001600160a01b031614156119bc576119b78d826120e3565b8b529b505b6119c9610b55864761234d565b815160208c8101919091529091015160408b01529950505050506001600160a01b03848116908a1614801590611a115750826001600160a01b0316896001600160a01b031614155b611a2d5760405162461bcd60e51b815260040161089f90613480565b611a388a8a89612893565b845115611b1f576040517f80feb3980000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906380feb39890611aa4908690600401613277565b60206040518083038186803b158015611abc57600080fd5b505afa158015611ad0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af491906130f2565b15611b0b578451611b06908590612a05565b611b1f565b8451611b1a9085908590612bcc565b600085525b6040516370a0823160e01b81526001600160a01b038516906370a0823190611b4b903090600401613277565b60206040518083038186803b158015611b6357600080fd5b505afa158015611b77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9b919061312d565b6040516370a0823160e01b81529092506001600160a01b038416906370a0823190611bca903090600401613277565b60206040518083038186803b158015611be257600080fd5b505afa158015611bf6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1a919061312d565b9050611c268282612576565b8515611c3657611c36338761267c565b886001600160a01b0316336001600160a01b03167f053d794b2310b8d186a24ae24a65ee066983a52a6efa6bd3df09a7601a3cb4f38a8a8e604051611c7d939291906137fd565b60405180910390a350506001600c555093969295509093509150565b600a54600b5491565b6040518060400160405280601081526020017f436f46695820506f6f6c20546f6b656e0000000000000000000000000000000081525081565b6000610861338484612765565b6000610f6982610c9985670de0b6b3a7640000612375565b633b9aca0081565b600c54600114611d2a5760405162461bcd60e51b815260040161089f906133a4565b6000600c556007546008546009546040516370a0823160e01b81526001600160a01b039384169390921691611ddf9184918691611dda916dffffffffffffffffffffffffffff9091169084906370a0823190611d8a903090600401613277565b60206040518083038186803b158015611da257600080fd5b505afa158015611db6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b1a919061312d565b612893565b611e408184611dda6009600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16856001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611d8a9190613277565b50506001600c5550565b600080611ea1611e6b84608001516305f5e10061234d90919063ffffffff16565b610c996305f5e100610c998760000151610c996305f5e1006114346116e28c606001516305f5e10061274090919063ffffffff16565b9150826080015160001461146a576114676305f5e100610c99611ed586606001516305f5e10061274090919063ffffffff16565b610c998760200151610c9989608001516114346305f5e1006114348d600001518d61237590919063ffffffff16565b7f000000000000000000000000000000000000000000000000000000000000000081565b6008546001600160a01b031681565b600080611f438361137c565b9050611f4f8482611ce8565b949350505050565b42841015611f775760405162461bcd60e51b815260040161089f90613582565b6003546001600160a01b03881660009081526004602090815260408083208054600181019091559051929392611fd8927f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9928d928d928d92918d910161333f565b60405160208183030381529060405280519060200120604051602001611fff929190613241565b60405160208183030381529060405280519060200120905060006001828686866040516000815260200160405260405161203c9493929190613373565b6020604051602081039080840390855afa15801561205e573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906120945750886001600160a01b0316816001600160a01b0316145b6120b05760405162461bcd60e51b815260040161089f906133db565b6120bb8989896122e5565b505050505050505050565b600260209081526000928352604080842090915290825290205481565b6000806121476305f5e100610c9961210c86606001516305f5e10061274090919063ffffffff16565b610c998760200151610c996121328a608001516305f5e10061234d90919063ffffffff16565b8a51611434906305f5e1009082908f90612375565b9150826080015160001461146a576114676305f5e100610c9961217b86606001516305f5e10061274090919063ffffffff16565b610c998760200151610c9989608001516114346305f5e1006114348d600001518f61237590919063ffffffff16565b600a5481565b600c546001146121d25760405162461bcd60e51b815260040161089f906133a4565b6000600c556007546040516370a0823160e01b81526122de916001600160a01b0316906370a0823190612209903090600401613277565b60206040518083038186803b15801561222157600080fd5b505afa158015612235573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612259919061312d565b6008546040516370a0823160e01b81526001600160a01b03909116906370a0823190612289903090600401613277565b60206040518083038186803b1580156122a157600080fd5b505afa1580156122b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122d9919061312d565b612576565b6001600c55565b6001600160a01b0380841660008181526002602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590612340908590613336565b60405180910390a3505050565b60008282111561236f5760405162461bcd60e51b815260040161089f90613449565b50900390565b60008261238457506000610865565b8282028284828161239157fe5b0414610f695760405162461bcd60e51b815260040161089f90613525565b60008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633018205f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561241057600080fd5b505afa158015612424573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124489190612ef2565b6001600160a01b0316638dba9329348a8a600481111561246457fe5b8a6040518563ffffffff1660e01b8152600401612483939291906132f7565b60a0604051808303818588803b15801561249c57600080fd5b505af11580156124b0573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906124d591906131ba565b939c929b5090995097509095509350505050565b6000546124f69082612740565b60009081556001600160a01b03831681526001602052604090205461251b9082612740565b6001600160a01b0383166000818152600160205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061256a908590613336565b60405180910390a35050565b6dffffffffffffffffffffffffffff82118015906125a257506dffffffffffffffffffffffffffff8111155b6125be5760405162461bcd60e51b815260040161089f90613760565b600980547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff848116919091177fffffffff0000000000000000000000000000ffffffffffffffffffffffffffff166e010000000000000000000000000000848316810291909117928390556040517f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad193612670938181169390910416906137ce565b60405180910390a15050565b604080516000808252602082019092526001600160a01b0384169083906040516126a69190613225565b60006040518083038185875af1925050503d80600081146126e3576040519150601f19603f3d011682016040523d82523d6000602084013e6126e8565b606091505b50509050806127095760405162461bcd60e51b815260040161089f906136cc565b505050565b600080821161272f5760405162461bcd60e51b815260040161089f906134b7565b81838161273857fe5b049392505050565b600082820183811015610f695760405162461bcd60e51b815260040161089f90613412565b6001600160a01b038316600090815260016020526040902054612788908261234d565b6001600160a01b0380851660009081526001602052604080822093909355908416815220546127b79082612740565b6001600160a01b0380841660008181526001602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612340908590613336565b6001600160a01b03821660009081526001602052604090205461282c908261234d565b6001600160a01b03831660009081526001602052604081209190915554612853908261234d565b60009081556040516001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061256a908590613336565b604080518082018252601981527f7472616e7366657228616464726573732c75696e743235362900000000000000602090910152516000906060906001600160a01b038616907fa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b9061290b90879087906024016132de565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516129769190613225565b6000604051808303816000865af19150503d80600081146129b3576040519150601f19603f3d011682016040523d82523d6000602084013e6129b8565b606091505b50915091508180156129e25750805115806129e25750808060200190518101906129e291906130f2565b6129fe5760405162461bcd60e51b815260040161089f90613729565b5050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e8a353926040518163ffffffff1660e01b815260040160206040518083038186803b158015612a6057600080fd5b505afa158015612a74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a989190612ef2565b90506001600160a01b038116612aae5750612bc8565b6040516370a0823160e01b81526000906001600160a01b038516906370a0823190612add903090600401613277565b60206040518083038186803b158015612af557600080fd5b505afa158015612b09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b2d919061312d565b905080831115612b3b578092505b6040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526001600160a01b03851690632e1a7d4d90612b80908690600401613336565b600060405180830381600087803b158015612b9a57600080fd5b505af1158015612bae573d6000803e3d6000fd5b505050506000831115612bc557612bc5828461267c565b50505b5050565b6040517f72b8cbcc0000000000000000000000000000000000000000000000000000000081526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906372b8cbcc90612c34908690600401613277565b60206040518083038186803b158015612c4c57600080fd5b505afa158015612c60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c849190612ef2565b90506001600160a01b038116612c9a5750612709565b612bc58482846040516370a0823160e01b81526000906001600160a01b038516906370a0823190612ccf903090600401613277565b60206040518083038186803b158015612ce757600080fd5b505afa158015612cfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d1f919061312d565b905080821115612d2d578091505b8115612bc557612bc5848484612893565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10612dae57805160ff1916838001178555612ddb565b82800160010185558215612ddb579182015b82811115612ddb578251825591602001919060010190612dc0565b50612de7929150612e09565b5090565b6040518060a001604052806005906020820280368337509192915050565b5b80821115612de75760008155600101612e0a565b600082601f830112612e2e578081fd5b813567ffffffffffffffff811115612e44578182fd5b612e576020601f19601f8401160161388b565b9150808252836020828501011115612e6e57600080fd5b8060208401602084013760009082016020015292915050565b600060a08284031215612e98578081fd5b612ea260a061388b565b9050813581526020820135602082015260408201356040820152606082013560608201526080820135608082015292915050565b600060208284031215612ee7578081fd5b8135610f69816138de565b600060208284031215612f03578081fd5b8151610f69816138de565b60008060408385031215612f20578081fd5b8235612f2b816138de565b91506020830135612f3b816138de565b809150509250929050565b60008060008060008060c08789031215612f5e578182fd5b8635612f69816138de565b95506020870135612f79816138de565b9450604087013567ffffffffffffffff80821115612f95578384fd5b612fa18a838b01612e1e565b95506060890135915080821115612fb6578384fd5b50612fc389828a01612e1e565b9350506080870135915060a087013590509295509295509295565b600080600060608486031215612ff2578283fd5b8335612ffd816138de565b9250602084013561300d816138de565b929592945050506040919091013590565b600080600080600080600060e0888a031215613038578081fd5b8735613043816138de565b96506020880135613053816138de565b95506040880135945060608801359350608088013560ff81168114613076578182fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156130a5578182fd5b82356130b0816138de565b946020939093013593505050565b6000806000606084860312156130d2578283fd5b83356130dd816138de565b95602085013595506040909401359392505050565b600060208284031215613103578081fd5b81518015158114610f69578182fd5b600060a08284031215613123578081fd5b610f698383612e87565b60006020828403121561313e578081fd5b5051919050565b60008060c08385031215613157578182fd5b823591506114678460208501612e87565b6000806040838503121561317a578182fd5b50508035926020909101359150565b6000806000806080858703121561319e578182fd5b5050823594602084013594506040840135936060013592509050565b600080600080600060a086880312156131d1578283fd5b5050835160208501516040860151606087015160809097015192989197509594509092509050565b600081518084526132118160208601602086016138b2565b601f01601f19169290920160200192915050565b600082516132378184602087016138b2565b9190910192915050565b7f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6001600160a01b03929092168252602082015260400190565b60006001600160a01b038516825260ff841660208301526060604083015261332260608301846131f9565b95945050505050565b901515815260200190565b90815260200190565b9586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b93845260ff9290921660208401526040830152606082015260800190565b600060208252610f6960208301846131f9565b6020808252600d908201527f43506169723a204c4f434b454400000000000000000000000000000000000000604082015260600190565b60208082526019908201527f4345524332303a20494e56414c49445f5349474e415455524500000000000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b60208082526011908201527f43506169723a20494e56414c49445f544f000000000000000000000000000000604082015260600190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b6020808252601a908201527f43506169723a20696e76616c696420617373657420726174696f000000000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60408201527f7700000000000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252600f908201527f4345524332303a20455850495245440000000000000000000000000000000000604082015260600190565b60208082526015908201527f43506169723a2077726f6e67206f7574546f6b656e0000000000000000000000604082015260600190565b60208082526016908201527f43506169723a20696c6c6567616c20616d6d6f756e7400000000000000000000604082015260600190565b6020808252601d908201527f43506169723a2053484f52545f4c49515549444954595f4255524e4544000000604082015260600190565b6020808252601d908201527f43506169723a2053484f52545f4c49515549444954595f4d494e544544000000604082015260600190565b60208082526010908201527f43506169723a20464f5242494444454e00000000000000000000000000000000604082015260600190565b60208082526023908201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960408201527f4c45440000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526016908201527f43506169723a205452414e534645525f4641494c454400000000000000000000604082015260600190565b6020808252600f908201527f43506169723a204f564552464c4f570000000000000000000000000000000000604082015260600190565b60208082526015908201527f43506169723a2077726f6e6720616d6f756e74496e0000000000000000000000604082015260600190565b6dffffffffffffffffffffffffffff92831681529116602082015260400190565b918252602082015260400190565b92835260208301919091526001600160a01b0316604082015260600190565b9283526020830191909152604082015260600190565b60006101008201905085825260208581840152846040840152606083018460005b600581101561387057815183529183019190830190600101613853565b5050505095945050505050565b60ff91909116815260200190565b60405181810167ffffffffffffffff811182821017156138aa57600080fd5b604052919050565b60005b838110156138cd5781810151838201526020016138b5565b83811115612bc55750506000910152565b6001600160a01b03811681146138f357600080fd5b5056fea264697066735822122075fd8b231a5e9a3ccabafbc24c4617be2296d370b66ce185fd035003fd69a2ba64736f6c634300060c0033a264697066735822122022300740a0ad249d4feb2a90147dc2d57d3ff358566d6c43f8ee49255b79d39364736f6c634300060c0033

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

000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

-----Decoded View---------------
Arg [0] : _WETH (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2


Deployed Bytecode Sourcemap

46815:6040:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47249:29;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;46983:51;;;;;;:::i;:::-;;:::i;51993:108::-;;;:::i;47041:34::-;;;;;;:::i;:::-;;:::i;48095:1179::-;;;;;;:::i;:::-;;:::i;51543:102::-;;;:::i;47322:18::-;;;:::i;47848:108::-;;;:::i;:::-;;;;;;;:::i;47118:25::-;;;:::i;47435:61::-;;;;;;:::i;:::-;;:::i;50305:263::-;;;;;;:::i;:::-;;:::i;:::-;;50576:279;;;;;;:::i;:::-;;:::i;47349:62::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;47285:28::-;;;:::i;47217:25::-;;;:::i;49557:263::-;;;;;;:::i;:::-;;:::i;52109:88::-;;;:::i;47964:123::-;;;:::i;49282:263::-;;;;;;:::i;:::-;;:::i;47082:29::-;;;:::i;47182:26::-;;;:::i;51875:110::-;;;:::i;50103:194::-;;;;;;:::i;:::-;;:::i;51765:102::-;;;:::i;51389:146::-;;;;;;:::i;:::-;;:::i;50863:275::-;;;;;;:::i;:::-;;:::i;51146:235::-;;;;;;:::i;:::-;;:::i;51653:104::-;;;:::i;49828:267::-;;;;;;:::i;:::-;;:::i;47150:25::-;;;:::i;47249:29::-;;;-1:-1:-1;;;;;47249:29:0;;:::o;46983:51::-;;;;;;;;;;;;;-1:-1:-1;;;;;46983:51:0;;:::o;51993:108::-;52080:13;;-1:-1:-1;;;;;52080:13:0;51993:108;:::o;47041:34::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;47041:34:0;;-1:-1:-1;47041:34:0;:::o;48095:1179::-;47591:10;;48224:12;;-1:-1:-1;;;;;47591:10:0;47577;:24;47569:58;;;;-1:-1:-1;;;47569:58:0;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;;;;;48257:19:0;::::1;48249:54;;;;-1:-1:-1::0;;;48249:54:0::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;48322:14:0;;::::1;48348:1;48322:14:::0;;;::::1;::::0;;;;;;;::::1;:28:::0;48314:62:::1;;;;-1:-1:-1::0;;;48314:62:0::1;;;;;;;:::i;:::-;48414:1;48395:16;:20;:44;;;;;48438:1;48419:16;:20;48395:44;48387:81;;;;-1:-1:-1::0;;;48387:81:0::1;;;;;;;:::i;:::-;48481:21;48505:30;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;48481:54;;48546:12;48588:5;48571:23;;;;;;;;:::i;:::-;;;;;;;;;;;;;48561:34;;;;;;48546:49;;48685:4;48674:8;48668:15;48663:2;48653:8;48649:17;48646:1;48638:52;48630:60:::0;-1:-1:-1;;;;;;48719:18:0;::::1;48711:57;;;;-1:-1:-1::0;;;48711:57:0::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;48781:14:0;;::::1;:7;:14:::0;;;::::1;::::0;;;;;;:21;;;;::::1;::::0;;;::::1;::::0;::::1;::::0;;;;48813:19;;;;::::1;::::0;;;;;;;;;::::1;::::0;;;;::::1;;::::0;;;48863:15;48889:18:::1;48910:17;48863:15:::0;48910:8:::1;:17::i;:::-;48889:38;;48938:19;48960:28;48967:14;;;;;;;;;;;;;;;;::::0;48983:4:::1;48960:6;:28::i;:::-;48938:50;;48999:21;49023:30;49030:16;;;;;;;;;;;;;;;;::::0;49048:4:::1;49023:6;:30::i;:::-;48999:54;;49077:4;-1:-1:-1::0;;;;;49064:29:0::1;;49094:4;49100:5;49107;49114:7;49123:16;49141;49064:94;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;49190:10:0::1;::::0;49171:46:::1;::::0;;;;-1:-1:-1;;;;;49190:10:0;;::::1;::::0;-1:-1:-1;49171:40:0::1;::::0;-1:-1:-1;49171:46:0::1;::::0;49212:4;;49171:46:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;49245:5;-1:-1:-1::0;;;;;49233:33:0::1;;49252:4;49258:7;49233:33;;;;;;;:::i;:::-;;;;;;;;47638:1;;;;;;48095:1179:::0;;;;;:::o;51543:102::-;51627:10;;-1:-1:-1;;;;;51627:10:0;51543:102;:::o;47322:18::-;;;-1:-1:-1;;;;;47322:18:0;;:::o;47848:108::-;47933:8;:15;47848:108;:::o;47118:25::-;;;-1:-1:-1;;;;;47118:25:0;;:::o;47435:61::-;;;;;;;;;;;;-1:-1:-1;;;;;47435:61:0;;:::o;50305:263::-;47591:10;;-1:-1:-1;;;;;47591:10:0;47577;:24;47569:58;;;;-1:-1:-1;;;47569:58:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;50394:18:0;::::1;50386:50;;;;-1:-1:-1::0;;;50386:50:0::1;;;;;;;:::i;:::-;50463:10;::::0;-1:-1:-1;;;;;50455:18:0;;::::1;50463:10:::0;::::1;50455:18;;50447:50;;;;-1:-1:-1::0;;;50447:50:0::1;;;;;;;:::i;:::-;50508:10;:17:::0;;;::::1;-1:-1:-1::0;;;;;50508:17:0;::::1;;::::0;;50541:19:::1;::::0;::::1;::::0;::::1;::::0;50508:17;;50541:19:::1;:::i;:::-;;;;;;;;50305:263:::0;:::o;50576:279::-;47591:10;;-1:-1:-1;;;;;47591:10:0;47577;:24;47569:58;;;;-1:-1:-1;;;47569:58:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;50669:18:0;::::1;50661:50;;;;-1:-1:-1::0;;;50661:50:0::1;;;;;;;:::i;:::-;50738:14;::::0;-1:-1:-1;;;;;50730:22:0;;::::1;50738:14:::0;::::1;50730:22;;50722:54;;;;-1:-1:-1::0;;;50722:54:0::1;;;;;;;:::i;:::-;50787:14;:21:::0;;;::::1;-1:-1:-1::0;;;;;50787:21:0;::::1;;::::0;;50824:23:::1;::::0;::::1;::::0;::::1;::::0;50787:21;;50824:23:::1;:::i;47349:62::-:0;;;;;;;;;;;;;;;:::o;47285:28::-;;;-1:-1:-1;;;;;47285:28:0;;:::o;47217:25::-;;;-1:-1:-1;;;;;47217:25:0;;:::o;49557:263::-;47591:10;;-1:-1:-1;;;;;47591:10:0;47577;:24;47569:58;;;;-1:-1:-1;;;47569:58:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;49646:18:0;::::1;49638:50;;;;-1:-1:-1::0;;;49638:50:0::1;;;;;;;:::i;:::-;49715:10;::::0;-1:-1:-1;;;;;49707:18:0;;::::1;49715:10:::0;::::1;49707:18;;49699:50;;;;-1:-1:-1::0;;;49699:50:0::1;;;;;;;:::i;:::-;49760:10;:17:::0;;;::::1;-1:-1:-1::0;;;;;49760:17:0;::::1;;::::0;;49793:19:::1;::::0;::::1;::::0;::::1;::::0;49760:17;;49793:19:::1;:::i;52109:88::-:0;52186:3;;-1:-1:-1;;;;;52186:3:0;52109:88;:::o;47964:123::-;48011:7;48048:30;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;48038:41;;;;;;48031:48;;47964:123;:::o;49282:263::-;47591:10;;-1:-1:-1;;;;;47591:10:0;47577;:24;47569:58;;;;-1:-1:-1;;;47569:58:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;49371:18:0;::::1;49363:50;;;;-1:-1:-1::0;;;49363:50:0::1;;;;;;;:::i;:::-;49440:10;::::0;-1:-1:-1;;;;;49432:18:0;;::::1;49440:10:::0;::::1;49432:18;;49424:50;;;;-1:-1:-1::0;;;49424:50:0::1;;;;;;;:::i;:::-;49485:10;:17:::0;;;::::1;-1:-1:-1::0;;;;;49485:17:0;::::1;;::::0;;49518:19:::1;::::0;::::1;::::0;::::1;::::0;49485:17;;49518:19:::1;:::i;47082:29::-:0;;;:::o;47182:26::-;;;-1:-1:-1;;;;;47182:26:0;;:::o;51875:110::-;51963:14;;-1:-1:-1;;;;;51963:14:0;51875:110;:::o;50103:194::-;47591:10;;-1:-1:-1;;;;;47591:10:0;47577;:24;47569:58;;;;-1:-1:-1;;;47569:58:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;50206:23:0;;::::1;;::::0;;;:16:::1;:23;::::0;;;;;;:34;;;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;50256:33;::::1;::::0;::::1;::::0;50206:23;;:34;;50256:33:::1;:::i;:::-;;;;;;;;50103:194:::0;;:::o;51765:102::-;51849:10;;-1:-1:-1;;;;;51849:10:0;51765:102;:::o;51389:146::-;47591:10;;-1:-1:-1;;;;;47591:10:0;47577;:24;47569:58;;;;-1:-1:-1;;;47569:58:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;51491:27:0;;;::::1;;::::0;;;:20:::1;:27;::::0;;;;:36;;;::::1;::::0;::::1;;::::0;;;::::1;::::0;;51389:146::o;50863:275::-;47591:10;;-1:-1:-1;;;;;47591:10:0;47577;:24;47569:58;;;;-1:-1:-1;;;47569:58:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;50955:18:0;::::1;50947:50;;;;-1:-1:-1::0;;;50947:50:0::1;;;;;;;:::i;:::-;51024:13;::::0;-1:-1:-1;;;;;51016:21:0;;::::1;51024:13:::0;::::1;51016:21;;51008:53;;;;-1:-1:-1::0;;;51008:53:0::1;;;;;;;:::i;:::-;51072:13;:20:::0;;;::::1;-1:-1:-1::0;;;;;51072:20:0;::::1;;::::0;;51108:22:::1;::::0;::::1;::::0;::::1;::::0;51072:20;;51108:22:::1;:::i;51146:235::-:0;47591:10;;-1:-1:-1;;;;;47591:10:0;47577;:24;47569:58;;;;-1:-1:-1;;;47569:58:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;51228:18:0;::::1;51220:50;;;;-1:-1:-1::0;;;51220:50:0::1;;;;;;;:::i;:::-;51297:3;::::0;-1:-1:-1;;;;;51289:11:0;;::::1;51297:3:::0;::::1;51289:11;;51281:43;;;;-1:-1:-1::0;;;51281:43:0::1;;;;;;;:::i;:::-;51335:3;:10:::0;;;::::1;-1:-1:-1::0;;;;;51335:10:0;::::1;;::::0;;51361:12:::1;::::0;::::1;::::0;::::1;::::0;51335:10;;51361:12:::1;:::i;51653:104::-:0;51738:11;;-1:-1:-1;;;;;51738:11:0;51653:104;:::o;49828:267::-;47591:10;;-1:-1:-1;;;;;47591:10:0;47577;:24;47569:58;;;;-1:-1:-1;;;47569:58:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;49918:18:0;::::1;49910:50;;;;-1:-1:-1::0;;;49910:50:0::1;;;;;;;:::i;:::-;49987:11;::::0;-1:-1:-1;;;;;49979:19:0;;::::1;49987:11:::0;::::1;49979:19;;49971:51;;;;-1:-1:-1::0;;;49971:51:0::1;;;;;;;:::i;:::-;50033:11;:18:::0;;;::::1;-1:-1:-1::0;;;;;50033:18:0;::::1;;::::0;;50067:20:::1;::::0;::::1;::::0;::::1;::::0;50033:18;;50067:20:::1;:::i;47150:25::-:0;;;-1:-1:-1;;;;;47150:25:0;;:::o;52384:468::-;52434:13;52464:7;52460:50;;-1:-1:-1;52488:10:0;;;;;;;;;;;;;;;;;;;52460:50;52529:2;52520:6;52561:69;52568:6;;52561:69;;52591:5;;52616:2;52611:7;;;;52561:69;;;52640:17;52670:3;52660:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;52660:14:0;-1:-1:-1;52640:34:0;-1:-1:-1;52694:7:0;;;52712:103;52719:7;;52712:103;;52776:2;52771;:7;52766:2;:12;52755:25;;52743:4;52748:3;;;;;;;52743:9;;;;;;;;;;;:37;;;;;;;;;;-1:-1:-1;52801:2:0;52795:8;;;;52712:103;;;-1:-1:-1;52839:4:0;-1:-1:-1;;;52384:468:0;;;;:::o;52232:144::-;52305:13;52362:1;52365;52345:22;;;;;;;;;:::i;:::-;;;;;;;;;;;;;52331:37;;52232:144;;;;;:::o;-1:-1:-1:-;;;;;;;;:::o;5:130::-;72:20;;-1:-1;;;;;12807:54;;13693:35;;13683:2;;13742:1;;13732:12;410:241;;514:2;502:9;493:7;489:23;485:32;482:2;;;-1:-1;;520:12;482:2;582:53;627:7;603:22;582:53;:::i;:::-;572:63;476:175;-1:-1;;;476:175::o;658:366::-;;;779:2;767:9;758:7;754:23;750:32;747:2;;;-1:-1;;785:12;747:2;847:53;892:7;868:22;847:53;:::i;:::-;837:63;;955:53;1000:7;937:2;980:9;976:22;955:53;:::i;:::-;945:63;;741:283;;;;;:::o;1031:360::-;;;1149:2;1137:9;1128:7;1124:23;1120:32;1117:2;;;-1:-1;;1155:12;1117:2;1217:53;1262:7;1238:22;1217:53;:::i;:::-;1207:63;;1307:2;1347:9;1343:22;206:20;13839:5;12640:13;12633:21;13817:5;13814:32;13804:2;;-1:-1;;13850:12;13804:2;1315:60;;;;1111:280;;;;;:::o;1398:491::-;;;;1536:2;1524:9;1515:7;1511:23;1507:32;1504:2;;;-1:-1;;1542:12;1504:2;1604:53;1649:7;1625:22;1604:53;:::i;:::-;1594:63;1694:2;1733:22;;340:20;;-1:-1;1802:2;1841:22;;;340:20;;1498:391;-1:-1;;;1498:391::o;1896:241::-;;2000:2;1988:9;1979:7;1975:23;1971:32;1968:2;;;-1:-1;;2006:12;1968:2;-1:-1;340:20;;1962:175;-1:-1;1962:175::o;2654:347::-;;2799:5;12109:12;12266:6;12261:3;12254:19;2893:52;2938:6;12303:4;12298:3;12294:14;12303:4;2919:5;2915:16;2893:52;:::i;:::-;13515:2;13495:14;13511:7;13491:28;2957:39;;;;12303:4;2957:39;;2746:255;-1:-1;;2746:255::o;5810:253::-;13606:2;13602:14;;;;;;2353:58;;6035:2;6026:12;;5926:137::o;6070:436::-;;3171:5;12109:12;3283:52;3328:6;3323:3;3316:4;3309:5;3305:16;3283:52;:::i;:::-;12109:12;;3347:16;;;;3283:52;12109:12;3347:16;3316:4;3305:16;;3283:52;:::i;:::-;3347:16;;6254:252;-1:-1;;;;6254:252::o;6513:222::-;-1:-1;;;;;12807:54;;;;2215:37;;6640:2;6625:18;;6611:124::o;6742:333::-;-1:-1;;;;;12807:54;;;2215:37;;12807:54;;7061:2;7046:18;;2215:37;6897:2;6882:18;;6868:207::o;7082:956::-;;-1:-1;;;;;12818:42;12811:5;12807:54;2222:3;2215:37;12818:42;12811:5;12807:54;7554:2;7543:9;7539:18;2215:37;;7389:3;7591:2;7580:9;7576:18;7569:48;7631:78;7389:3;7378:9;7374:19;7695:6;7631:78;:::i;:::-;7757:9;7751:4;7747:20;7742:2;7731:9;7727:18;7720:48;7782:78;7855:4;7846:6;7782:78;:::i;:::-;7939:3;7924:19;;2605:37;;;;-1:-1;;8023:3;8008:19;2605:37;7774:86;7360:678;-1:-1;;;;7360:678::o;8045:333::-;-1:-1;;;;;12807:54;;;;2215:37;;8364:2;8349:18;;2605:37;8200:2;8185:18;;8171:207::o;8385:210::-;12640:13;;12633:21;2488:34;;8506:2;8491:18;;8477:118::o;8602:222::-;2605:37;;;8729:2;8714:18;;8700:124::o;8831:416::-;9031:2;9045:47;;;3600:2;9016:18;;;12254:19;3636:24;12294:14;;;3616:45;3680:12;;;9002:245::o;9254:416::-;9454:2;9468:47;;;3931:2;9439:18;;;12254:19;3967:21;12294:14;;;3947:42;4008:12;;;9425:245::o;9677:416::-;9877:2;9891:47;;;4259:2;9862:18;;;12254:19;4295:23;12294:14;;;4275:44;4338:12;;;9848:245::o;10100:416::-;10300:2;10314:47;;;4589:2;10285:18;;;12254:19;4625:28;12294:14;;;4605:49;4673:12;;;10271:245::o;10523:416::-;10723:2;10737:47;;;4924:2;10708:18;;;12254:19;4960:23;12294:14;;;4940:44;5003:12;;;10694:245::o;10946:416::-;11146:2;11160:47;;;5254:2;11131:18;;;12254:19;5290:26;12294:14;;;5270:47;5336:12;;;11117:245::o;11369:416::-;11569:2;11583:47;;;5587:2;11554:18;;;12254:19;5623:21;12294:14;;;5603:42;5664:12;;;11540:245::o;12953:268::-;13018:1;13025:101;13039:6;13036:1;13033:13;13025:101;;;13106:11;;;13100:18;13087:11;;;13080:39;13061:2;13054:10;13025:101;;;13141:6;13138:1;13135:13;13132:2;;;13018:1;13197:6;13192:3;13188:16;13181:27;13132:2;;13002:219;;;:::o

Swarm Source

ipfs://22300740a0ad249d4feb2a90147dc2d57d3ff358566d6c43f8ee49255b79d393

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.