ETH Price: $3,468.19 (+2.18%)
Gas: 14 Gwei

Token

XToken 1 (XT-1)
 

Overview

Max Total Supply

1,080.24667640828329404 XT-1

Holders

229

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Balance
0.000000009999995 XT-1

Value
$0.00
0xe516a08a8588f26fd2bee405fc75191a3ef367bb
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
CoFiXPair

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 6666 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2020-10-12
*/

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

/**

Author: CoFiX Core, https://cofix.io
Commit hash: v0.9.5-1-g7141c43
Repository: https://github.com/Computable-Finance/CoFiX
Issues: https://github.com/Computable-Finance/CoFiX/issues

*/

pragma experimental ABIEncoderV2;
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;
}

// 
interface ICoFiXPair 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) external payable returns (uint liquidity, uint oracleFeeChange);
    function burn(address outToken, address to) external payable returns (uint amountOut, uint oracleFeeChange);
    function swapWithExact(address outToken, address to) external payable returns (uint amountIn, uint amountOut, uint oracleFeeChange, uint256[4] 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) 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);
}

// 
interface ICoFiXFactory {
    // 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);

    /// @dev Create a new token pair for trading
    /// @param  token the address of token to trade
    /// @return pair the address of new token pair
    function createPair(
        address token
        )
        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 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);
}

// 
interface ICoFiXController {

    event NewK(address token, int128 K, int128 sigma, uint256 T, uint256 ethAmount, uint256 erc20Amount, uint256 blockNum, uint256 tIdx, uint256 sigmaIdx, int128 K0);
    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);

    function addCaller(address caller) external;

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

// 
/**
 * @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);
}

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

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

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

// 
// Pair contract for each trading pair, storing assets and handling settlement
// No owner or governance
contract CoFiXPair is ICoFiXPair, 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

    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) external override {
        require(msg.sender == factory, "CPair: FORBIDDEN"); // sufficient check
        token0 = _token0;
        token1 = _token1;
        name = _name;
        symbol = _symbol;
    }

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

        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 = calcNAVPerShareForMint(_reserve0, _reserve1, _op);
            if (totalSupply == 0) {
                liquidity = calcLiquidity(amount0, amount1, navps, _op).sub(MINIMUM_LIQUIDITY);
                _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
            } else {
                liquidity = calcLiquidity(amount0, amount1, navps, _op);
            }
        }
        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 outToken, address to) external payable override lock returns (uint amountOut, 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, outToken, to, liquidity);
            // query price
            OraclePrice memory _op;
            (_op.K, _op.ethAmount, _op.erc20Amount, _op.blockNum, _op.theta) = _queryOracle(_token1, CoFiX_OP.BURN, data);
            if (outToken == _token0) {
                (amountOut, fee) = calcOutToken0ForBurn(liquidity, _op); // navps calculated
            } else if (outToken == _token1) {
                (amountOut, fee) = calcOutToken1ForBurn(liquidity, _op); // navps calculated
            }  else {
                revert("CPair: wrong outToken");
            }
        }
        oracleFeeChange = msg.value.sub(_ethBalanceBefore.sub(address(this).balance));

        require(amountOut > 0, "CPair: SHORT_LIQUIDITY_BURNED");
        _burn(address(this), liquidity);
        _safeTransfer(outToken, to, amountOut);
        if (fee > 0) {
            if (ICoFiXFactory(factory).getTradeMiningStatus(_token1)) {
                // only transfer fee to protocol feeReceiver when trade mining is enabled for this trading pair
                _safeSendFeeForCoFiHolder(_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, outToken, amountOut, to);
    }


    // 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[4] memory tradeInfo)
    {
        // tradeInfo[0]: thetaFee, tradeInfo[1]: x, tradeInfo[2]: y, tradeInfo[3]: navps
        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);
                tradeInfo[1] = _reserve0; // swap token0 for token1 out
                tradeInfo[2] = uint256(_reserve1).mul(_op.ethAmount).div(_op.erc20Amount); // _reserve1 value as _reserve0
            } else if (outToken == _token0) {
                (amountOut, tradeInfo[0]) = calcOutToken0(amountIn, _op);
                tradeInfo[1] = uint256(_reserve1).mul(_op.ethAmount).div(_op.erc20Amount); // _reserve1 value as _reserve0
                tradeInfo[2] = _reserve0; // swap token1 for token0 out
            }
            oracleFeeChange = msg.value.sub(_ethBalanceBefore.sub(address(this).balance));
            tradeInfo[3] = calcNAVPerShare(_reserve0, _reserve1, _op.ethAmount, _op.erc20Amount);
        }
        
        require(to != _token0 && to != _token1, "CPair: INVALID_TO");

        _safeTransfer(outToken, to, amountOut); // optimistically transfer tokens
        if (tradeInfo[0] > 0) {
            if (ICoFiXFactory(factory).getTradeMiningStatus(_token1)) {
                // only transfer fee to protocol feeReceiver when trade mining is enabled for this trading pair
                _safeSendFeeForCoFiHolder(_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);
    }

    // this low-level function should be called from a contract which performs important safety checks
    function swapForExact(address outToken, uint amountOutExact, address to)
        external
        payable override lock
        returns (uint amountIn, uint amountOut, uint oracleFeeChange, uint256[4] memory tradeInfo)
    {
        // tradeInfo[0]: thetaFee, tradeInfo[1]: x, tradeInfo[2]: y, tradeInfo[3]: navps
        address _token0 = token0;
        address _token1 = token1;
        OraclePrice memory _op;

        // uint256 fee;

        { // scope for ethAmount/erc20Amount/blockNum to avoid stack too deep error
            uint256 _ethBalanceBefore = address(this).balance;
            bytes memory data = abi.encode(msg.sender, outToken, amountOutExact, to);
            // query price
            (_op.K, _op.ethAmount, _op.erc20Amount, _op.blockNum, _op.theta) = _queryOracle(_token1, CoFiX_OP.SWAP_FOR_EXACT, data);
            oracleFeeChange = msg.value.sub(_ethBalanceBefore.sub(address(this).balance));
        }

        { // calc and check amountIn, also outToken
            uint256 balance0 = IERC20(_token0).balanceOf(address(this));
            uint256 balance1 = IERC20(_token1).balanceOf(address(this));
            (uint112 _reserve0, uint112 _reserve1) = getReserves(); // gas savings
     
            if (outToken == _token1) {
                amountIn = balance0.sub(_reserve0);
                tradeInfo[1] = _reserve0; // swap token0 for token1 out
                tradeInfo[2] = uint256(_reserve1).mul(_op.ethAmount).div(_op.erc20Amount); // _reserve1 value as _reserve0
            } else if (outToken == _token0) {
                amountIn = balance1.sub(_reserve1);
                tradeInfo[1] = uint256(_reserve1).mul(_op.ethAmount).div(_op.erc20Amount); // _reserve1 value as _reserve0
                tradeInfo[2] = _reserve0; // swap token1 for token0 out
            } else {
                revert("CPair: wrong outToken");
            }
            require(amountIn > 0, "CPair: wrong amountIn");
            tradeInfo[3] = calcNAVPerShare(_reserve0, _reserve1, _op.ethAmount, _op.erc20Amount);
        }

        { // split with branch upbove to make code more clear
            uint _amountInNeeded;
            uint _amountInLeft;
            if (outToken == _token1) {
                (_amountInNeeded, tradeInfo[0]) = calcInNeededToken0(amountOutExact, _op);
                _amountInLeft = amountIn.sub(_amountInNeeded);
                if (_amountInLeft > 0) {
                    _safeTransfer(_token0, to, _amountInLeft); // send back the amount0 token change
                }
            } else if (outToken == _token0) {
                (_amountInNeeded, tradeInfo[0]) = calcInNeededToken1(amountOutExact, _op);
                _amountInLeft = amountIn.sub(_amountInNeeded);
                if (_amountInLeft > 0) {
                    _safeTransfer(_token1, to, _amountInLeft); // send back the amount1 token change
                }
            }
            require(_amountInNeeded <= amountIn, "CPair: insufficient amountIn");
            require(_amountInNeeded > 0, "CPair: wrong amountIn needed");
        }
        
        {
            require(to != _token0 && to != _token1, "CPair: INVALID_TO");

            amountOut = amountOutExact;
            _safeTransfer(outToken, to, amountOut); // optimistically transfer tokens
            if (tradeInfo[0] > 0) {
                if (ICoFiXFactory(factory).getTradeMiningStatus(_token1)) {
                    // only transfer fee to protocol feeReceiver when trade mining is enabled for this trading pair
                    _safeSendFeeForCoFiHolder(_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)
                }
            }
            uint256 balance0 = IERC20(_token0).balanceOf(address(this));
            uint256 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 for mint
    // use it in this contract, for optimized gas usage
    function calcNAVPerShareForMint(uint256 balance0, uint256 balance1, OraclePrice memory _op) public view returns (uint256 navps) {
        uint _totalSupply = totalSupply;
        if (_totalSupply == 0) {
            navps = NAVPS_BASE;
        } else {
            /*
            N_{p} &= (A_{u}/P_{s}^{'} + A_{e})/S \\\\
                  &= (A_{u}/(P * (1 - K)) + A_{e})/S \\\\
                  &= (\frac{A_{u}}{\frac{erc20Amount}{ethAmount} * \frac{(k_{BASE} - k)}{(k_{BASE})}} + A_{e})/S \\\\
                  &= (\frac{A_{u}*ethAmount*k_{BASE}}{erc20Amount*(k_{BASE} - k)}+ A_{e}) / S \\\\
                  &= (A_{u}*ethAmount*k_{BASE}+ A_{e}*erc20Amount*(k_{BASE} - k)) / S / (erc20Amount*(k_{BASE} - k)) \\\\
            N_{p} &= NAVPS_{BASE}*(A_{u}*ethAmount*k_{BASE}+ A_{e}*erc20Amount*(k_{BASE} - k)) / S / (erc20Amount*(k_{BASE} - k)) \\\\
            // navps = NAVPS_BASE * ( (balance1*_op.ethAmount*K_BASE) + (balance0*_op.erc20Amount*(K_BASE-_op.K)) ) / _totalSupply / _op.erc20Amount / (K_BASE-_op.K);
            */
            uint256 kbaseSubK = K_BASE.sub(_op.K);
            uint256 balance1MulEthKbase = balance1.mul(_op.ethAmount).mul(K_BASE);
            uint256 balance0MulErcKbsk = balance0.mul(_op.erc20Amount).mul(kbaseSubK);
            navps = NAVPS_BASE.mul( (balance1MulEthKbase).add(balance0MulErcKbsk) ).div(_totalSupply).div(_op.erc20Amount).div(kbaseSubK);
        }
    }

    // calc Net Asset Value Per Share for burn
    // use it in this contract, for optimized gas usage
    function calcNAVPerShareForBurn(uint256 balance0, uint256 balance1, OraclePrice memory _op) public view returns (uint256 navps) {
        uint _totalSupply = totalSupply;
        if (_totalSupply == 0) {
            navps = NAVPS_BASE;
        } else {
            /*
            N_{p}^{'} &= (A_{u}/P_{b}^{'} + A_{e})/S \\\\
                      &= (A_{u}/(P * (1 + K)) + A_{e})/S \\\\
                      &= (\frac{A_{u}}{\frac{erc20Amount}{ethAmount} * \frac{(k_{BASE} + k)}{(k_{BASE})}} + A_{e})/S \\\\
                      &= (\frac{A_{u}*ethAmount*k_{BASE}}{erc20Amount*(k_{BASE} + k)}+ A_{e}) / S \\\\
                      &= (A_{u}*ethAmount*k_{BASE}+ A_{e}*erc20Amount*(k_{BASE} + k)) / S / (erc20Amount*(k_{BASE} + k)) \\\\
            N_{p}^{'} &= NAVPS_{BASE}*(A_{u}*ethAmount*k_{BASE}+ A_{e}*erc20Amount*(k_{BASE} + k)) / S / (erc20Amount*(k_{BASE} + k)) \\\\
            // navps = NAVPS_BASE * ( (balance1*_op.ethAmount*K_BASE) + (balance0*_op.erc20Amount*(K_BASE+_op.K)) ) / _totalSupply / _op.erc20Amount / (K_BASE+_op.K);
            */
            uint256 kbaseAddK = K_BASE.add(_op.K);
            uint256 balance1MulEthKbase = balance1.mul(_op.ethAmount).mul(K_BASE);
            uint256 balance0MulErcKbsk = balance0.mul(_op.erc20Amount).mul(kbaseAddK);
            navps = NAVPS_BASE.mul( (balance1MulEthKbase).add(balance0MulErcKbsk) ).div(_totalSupply).div(_op.erc20Amount).div(kbaseAddK);
        }
    }

    // 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 {
            /*
            N_{p}^{'} &= (A_{u}/P + A_{e})/S \\\\
                      &= (\frac{A_{u}}{\frac{erc20Amount}{ethAmount}} + A_{e})/S \\\\
                      &= (\frac{A_{u}*ethAmount}{erc20Amount}+ A_{e}) / S \\\\
                      &= (A_{u}*ethAmount+ A_{e}*erc20Amount) / S / (erc20Amount) \\\\
            N_{p}^{'} &= NAVPS_{BASE}*(A_{u}*ethAmount+ A_{e}*erc20Amount) / S / (erc20Amount) \\\\
            // navps = NAVPS_BASE * ( (balance1*_op.ethAmount) + (balance0*_op.erc20Amount) ) / _totalSupply / _op.erc20Amount;
            */
            uint256 balance1MulEth = balance1.mul(ethAmount);
            uint256 balance0MulErc = balance0.mul(erc20Amount);
            navps = NAVPS_BASE.mul( (balance1MulEth).add(balance0MulErc) ).div(_totalSupply).div(erc20Amount);
        }
    }

    // use it in this contract, for optimized gas usage
    function calcLiquidity(uint256 amount0, uint256 amount1, uint256 navps, OraclePrice memory _op) public pure returns (uint256 liquidity) {
        /*
        s_{1} &= a / (N_{p} / NAVPS_{BASE}) \\\\
              &= a * NAVPS_{BASE} / N_{p} \\\\
        s_{2} &= b / P_{b}^{'} / (N_{p} / NAVPS_{BASE}) \\\\
              &= b / (N_{p} / NAVPS_{BASE}) / P_{b}^{'} \\\\
              &= b * NAVPS_{BASE} / N_{p} / P_{b}^{'} \\\\
              &= b * NAVPS_{BASE} / N_{p} / (\frac{erc20Amount}{ethAmount} * \frac{(k_{BASE} + k)}{(k_{BASE})}) \\\\
              &= b * NAVPS_{BASE} * ethAmount * k_{BASE} / N_{p} / (erc20Amount * (k_{BASE} + k))
        s &= s_1 + s_2 \\\\
          &= a * NAVPS_{BASE} / N_{p} + b * NAVPS_{BASE} / N_{p} / P_{b}^{'} \\\\
          &= a * NAVPS_{BASE} / N_{p} + b * NAVPS_{BASE} * ethAmount * k_{BASE} / N_{p} / (erc20Amount * (k_{BASE} + k)) \\\\
        // liquidity = (amount0 * NAVPS_BASE / navps) + (amount1 * NAVPS_BASE * _op.ethAmount * K_BASE / navps / _op.erc20Amount / (K_BASE + _op.K));
        */
        uint256 amnt0MulNbaseDivN = amount0.mul(NAVPS_BASE).div(navps);
        uint256 amnt1MulNbaseEthKbase = amount1.mul(NAVPS_BASE).mul(_op.ethAmount).mul(K_BASE);
        liquidity = ( amnt0MulNbaseDivN ).add( amnt1MulNbaseEthKbase.div(navps).div(_op.erc20Amount).div(K_BASE.add(_op.K)) );
    }

    // 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 calcNAVPerShareForMint(reserve0, reserve1, _op);
    }

    // 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 calcNAVPerShareForBurn(reserve0, reserve1, _op);
    }

    // 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, uint256 amount1, OraclePrice memory _op) external view returns (uint256 liquidity) {
        uint256 navps = getNAVPerShareForMint(_op);
        return calcLiquidity(amount0, amount1, navps, _op);
    }

    // calc amountOut for token0 (WETH) when send liquidity token to pool for burning
    function calcOutToken0ForBurn(uint256 liquidity, OraclePrice memory _op) public view returns (uint256 amountOut, uint256 fee) {
        /*
        e &= c * (N_{p}^{'} / NAVPS_{BASE}) * (THETA_{BASE} - \theta)/THETA_{BASE} \\\\
          &= c * \frac{N_{p}^{'}}{NAVPS_{BASE}} * \frac{THETA_{BASE} - \theta}{THETA_{BASE}} \\\\
          &= c * N_{p}^{'} * (THETA_{BASE} - \theta) / NAVPS_{BASE} / THETA_{BASE} \\\\
        // amountOut = liquidity * navps * (THETA_BASE - _op.theta) / NAVPS_BASE / THETA_BASE;
        */
        uint256 navps = calcNAVPerShareForBurn(reserve0, reserve1, _op);
        amountOut = liquidity.mul(navps).mul(THETA_BASE.sub(_op.theta)).div(NAVPS_BASE).div(THETA_BASE);
        if (_op.theta != 0) {
            // fee = liquidity * navps * (_op.theta) / NAVPS_BASE / THETA_BASE;
            fee = liquidity.mul(navps).mul(_op.theta).div(NAVPS_BASE).div(THETA_BASE);
        }
        return (amountOut, fee);
    }


    // calc amountOut for token1 (ERC20 token) when send liquidity token to pool for burning
    function calcOutToken1ForBurn(uint256 liquidity, OraclePrice memory _op) public view returns (uint256 amountOut, uint256 fee) {
        /*
        u &= c * (N_{p}^{'} / NAVPS_{BASE}) * P_{s}^{'} * (THETA_{BASE} - \theta)/THETA_{BASE} \\\\
          &= c * \frac{N_{p}^{'}}{NAVPS_{BASE}} * \frac{erc20Amount}{ethAmount} * \frac{(k_{BASE} - k)}{(k_{BASE})} * \frac{THETA_{BASE} - \theta}{THETA_{BASE}} \\\\
          &= \frac{c * N_{p}^{'} * erc20Amount * (k_{BASE} - k) * (THETA_{BASE} - \theta)}{NAVPS_{BASE}*ethAmount*k_{BASE}*THETA_{BASE}}
        // amountOut = liquidity * navps * _op.erc20Amount * (K_BASE - _op.K) * (THETA_BASE - _op.theta) / NAVPS_BASE / _op.ethAmount / K_BASE / THETA_BASE;
        */
        uint256 navps = calcNAVPerShareForBurn(reserve0, reserve1, _op);
        uint256 liqMulMany = liquidity.mul(navps).mul(_op.erc20Amount).mul(K_BASE.sub(_op.K)).mul(THETA_BASE.sub(_op.theta));
        amountOut = liqMulMany.div(NAVPS_BASE).div(_op.ethAmount).div(K_BASE).div(THETA_BASE);
        if (_op.theta != 0) {
            // fee = liquidity * navps * (_op.theta) / NAVPS_BASE / THETA_BASE;
            fee = liquidity.mul(navps).mul(_op.theta).div(NAVPS_BASE).div(THETA_BASE);
        }
        return (amountOut, fee);
    }

    // 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 ICoFiXController(ICoFiXFactory(factory).getController()).queryOracle{value: msg.value}(token, uint8(op), data);
    }

    // Safe WETH transfer function, just in case not having enough WETH. CoFi holder will earn these fees.
    function _safeSendFeeForCoFiHolder(address _token0, uint256 _fee) internal {
        address feeReceiver = ICoFiXFactory(factory).getFeeReceiver();
        if (feeReceiver == address(0)) {
            return; // if feeReceiver not set, theta fee keeps in pair pool
        }
        _safeSendFee(_token0, feeReceiver, _fee); // transfer fee to protocol fee reward pool for CoFi holders
    }

    // 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 = ICoFiXFactory(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); 
    }
}

// UNI & CoFi Rocks

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"outToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"outAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"address","name":"outToken","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint112","name":"reserve0","type":"uint112"},{"indexed":false,"internalType":"uint112","name":"reserve1","type":"uint112"}],"name":"Sync","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"K_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_LIQUIDITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAVPS_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"THETA_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"outToken","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"burn","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"oracleFeeChange","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"components":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"erc20Amount","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"uint256","name":"K","type":"uint256"},{"internalType":"uint256","name":"theta","type":"uint256"}],"internalType":"struct ICoFiXPair.OraclePrice","name":"_op","type":"tuple"}],"name":"calcInNeededToken0","outputs":[{"internalType":"uint256","name":"amountInNeeded","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"components":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"erc20Amount","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"uint256","name":"K","type":"uint256"},{"internalType":"uint256","name":"theta","type":"uint256"}],"internalType":"struct ICoFiXPair.OraclePrice","name":"_op","type":"tuple"}],"name":"calcInNeededToken1","outputs":[{"internalType":"uint256","name":"amountInNeeded","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"},{"internalType":"uint256","name":"navps","type":"uint256"},{"components":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"erc20Amount","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"uint256","name":"K","type":"uint256"},{"internalType":"uint256","name":"theta","type":"uint256"}],"internalType":"struct ICoFiXPair.OraclePrice","name":"_op","type":"tuple"}],"name":"calcLiquidity","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"balance0","type":"uint256"},{"internalType":"uint256","name":"balance1","type":"uint256"},{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"erc20Amount","type":"uint256"}],"name":"calcNAVPerShare","outputs":[{"internalType":"uint256","name":"navps","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"balance0","type":"uint256"},{"internalType":"uint256","name":"balance1","type":"uint256"},{"components":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"erc20Amount","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"uint256","name":"K","type":"uint256"},{"internalType":"uint256","name":"theta","type":"uint256"}],"internalType":"struct ICoFiXPair.OraclePrice","name":"_op","type":"tuple"}],"name":"calcNAVPerShareForBurn","outputs":[{"internalType":"uint256","name":"navps","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"balance0","type":"uint256"},{"internalType":"uint256","name":"balance1","type":"uint256"},{"components":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"erc20Amount","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"uint256","name":"K","type":"uint256"},{"internalType":"uint256","name":"theta","type":"uint256"}],"internalType":"struct ICoFiXPair.OraclePrice","name":"_op","type":"tuple"}],"name":"calcNAVPerShareForMint","outputs":[{"internalType":"uint256","name":"navps","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"components":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"erc20Amount","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"uint256","name":"K","type":"uint256"},{"internalType":"uint256","name":"theta","type":"uint256"}],"internalType":"struct ICoFiXPair.OraclePrice","name":"_op","type":"tuple"}],"name":"calcOutToken0","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"},{"components":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"erc20Amount","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"uint256","name":"K","type":"uint256"},{"internalType":"uint256","name":"theta","type":"uint256"}],"internalType":"struct ICoFiXPair.OraclePrice","name":"_op","type":"tuple"}],"name":"calcOutToken0ForBurn","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"components":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"erc20Amount","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"uint256","name":"K","type":"uint256"},{"internalType":"uint256","name":"theta","type":"uint256"}],"internalType":"struct ICoFiXPair.OraclePrice","name":"_op","type":"tuple"}],"name":"calcOutToken1","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"},{"components":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"erc20Amount","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"uint256","name":"K","type":"uint256"},{"internalType":"uint256","name":"theta","type":"uint256"}],"internalType":"struct ICoFiXPair.OraclePrice","name":"_op","type":"tuple"}],"name":"calcOutToken1ForBurn","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"},{"components":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"erc20Amount","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"uint256","name":"K","type":"uint256"},{"internalType":"uint256","name":"theta","type":"uint256"}],"internalType":"struct ICoFiXPair.OraclePrice","name":"_op","type":"tuple"}],"name":"getLiquidity","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"erc20Amount","type":"uint256"}],"name":"getNAVPerShare","outputs":[{"internalType":"uint256","name":"navps","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"erc20Amount","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"uint256","name":"K","type":"uint256"},{"internalType":"uint256","name":"theta","type":"uint256"}],"internalType":"struct ICoFiXPair.OraclePrice","name":"_op","type":"tuple"}],"name":"getNAVPerShareForBurn","outputs":[{"internalType":"uint256","name":"navps","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"erc20Amount","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"uint256","name":"K","type":"uint256"},{"internalType":"uint256","name":"theta","type":"uint256"}],"internalType":"struct ICoFiXPair.OraclePrice","name":"_op","type":"tuple"}],"name":"getNAVPerShareForMint","outputs":[{"internalType":"uint256","name":"navps","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint112","name":"_reserve0","type":"uint112"},{"internalType":"uint112","name":"_reserve1","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token0","type":"address"},{"internalType":"address","name":"_token1","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"oracleFeeChange","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nameForDomain","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"skim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"outToken","type":"address"},{"internalType":"uint256","name":"amountOutExact","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"swapForExact","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"oracleFeeChange","type":"uint256"},{"internalType":"uint256[4]","name":"tradeInfo","type":"uint256[4]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"outToken","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"swapWithExact","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"oracleFeeChange","type":"uint256"},{"internalType":"uint256[4]","name":"tradeInfo","type":"uint256[4]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sync","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60a06040526001600a553480156200001657600080fd5b50604080518082018252601081526f21b7a334ac102837b7b6102a37b5b2b760811b6020918201528151808301835260018152603160f81b9082015290514691620000cc917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f917f70f1d8d3a2b874a116643bbbdb7e2937ce56e0359f9c3070aac2ec77a8354ccc917fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6918691309101620000f5565b60408051601f198184030181529190528051602090910120600355503360601b60805262000121565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b60805160601c61410362000162600039806108db5280610d115280611a0052806120a652806125ae5280612c885280612fbd52806130a652506141036000f3fe6080604052600436106102e05760003560e01c806395d89b4111610184578063bc25cf77116100d6578063d505accf1161008a578063e5eac39011610064578063e5eac39014610776578063eb77289914610796578063fff6cae9146107b6576102e7565b8063d505accf14610716578063dd2e0a3114610736578063dd62ed3e14610756576102e7565b8063bf36aac2116100bb578063bf36aac2146106cc578063c45a0155146106ec578063d21220a714610701576102e7565b8063bc25cf771461068c578063be5b32f8146106ac576102e7565b8063a661dbda11610138578063b2874f8711610112578063b2874f8714610637578063b72bda4a14610657578063ba9a7a5614610677576102e7565b8063a661dbda14610602578063a9059cbb14610617578063aaf07e9214610465576102e7565b80639c673c52116101695780639c673c52146105ac5780639f44296a146105cc578063a12db6cc146105ef576102e7565b806395d89b411461057757806399f45e481461058c576102e7565b8063313ce5671161023d5780634f6ec2dd116101f15780636a627842116101cb5780636a6278421461052457806370a08231146105375780637ecebe0014610557576102e7565b80634f6ec2dd146104cf5780635ad6bd30146104e4578063663eda1f14610504576102e7565b80633644e515116102225780633644e5151461047a57806339818b661461048f57806349a23da0146104af576102e7565b8063313ce567146104435780633298613114610465576102e7565b80632016a0d21161029457806324334be81161027957806324334be8146103ed57806327fc84a31461040d57806330adf81f1461042e576102e7565b80632016a0d2146103ab57806323b872dd146103cd576102e7565b8063095ea7b3116102c5578063095ea7b31461033a5780630dfe16811461036757806318160ddd14610389576102e7565b806306fdde03146102ec5780630902f1ac14610317576102e7565b366102e757005b600080fd5b3480156102f857600080fd5b506103016107cb565b60405161030e9190613bed565b60405180910390f35b34801561032357600080fd5b5061032c610877565b60405161030e929190613fbc565b34801561034657600080fd5b5061035a61035536600461384b565b6108a4565b60405161030e9190613b87565b34801561037357600080fd5b5061037c6108bb565b60405161030e9190613ab1565b34801561039557600080fd5b5061039e6108ca565b60405161030e9190613b92565b3480156103b757600080fd5b506103cb6103c6366004613710565b6108d0565b005b3480156103d957600080fd5b5061035a6103e8366004613796565b610997565b3480156103f957600080fd5b5061039e61040836600461392d565b610a49565b61042061041b3660046136d8565b610a87565b60405161030e929190613fdd565b34801561043a57600080fd5b5061039e610f2f565b34801561044f57600080fd5b50610458610f53565b60405161030e9190614054565b34801561047157600080fd5b5061039e610f58565b34801561048657600080fd5b5061039e610f60565b34801561049b57600080fd5b5061039e6104aa3660046138d7565b610f66565b3480156104bb57600080fd5b5061039e6104ca36600461394e565b610f98565b3480156104db57600080fd5b5061039e611061565b3480156104f057600080fd5b506104206104ff36600461390a565b61106d565b34801561051057600080fd5b5061039e61051f366004613983565b611112565b6104206105323660046136a0565b6111a0565b34801561054357600080fd5b5061039e6105523660046136a0565b6114a0565b34801561056357600080fd5b5061039e6105723660046136a0565b6114b2565b34801561058357600080fd5b506103016114c4565b34801561059857600080fd5b5061039e6105a73660046139c3565b61153d565b3480156105b857600080fd5b506104206105c736600461390a565b611593565b6105df6105da3660046136d8565b611627565b60405161030e949392919061400a565b6105df6105fd366004613876565b611c33565b34801561060e57600080fd5b506103016122d3565b34801561062357600080fd5b5061035a61063236600461384b565b61230c565b34801561064357600080fd5b5061039e61065236600461394e565b612319565b34801561066357600080fd5b5061039e61067236600461394e565b61233c565b34801561068357600080fd5b5061039e612372565b34801561069857600080fd5b506103cb6106a73660046136a0565b61237a565b3480156106b857600080fd5b5061039e6106c73660046138d7565b6124bc565b3480156106d857600080fd5b506104206106e736600461390a565b6124f2565b3480156106f857600080fd5b5061037c6125ac565b34801561070d57600080fd5b5061037c6125d0565b34801561072257600080fd5b506103cb6107313660046137d6565b6125df565b34801561074257600080fd5b5061042061075136600461390a565b61274e565b34801561076257600080fd5b5061039e6107713660046136d8565b612857565b34801561078257600080fd5b5061042061079136600461390a565b612874565b3480156107a257600080fd5b506104206107b136600461390a565b61293b565b3480156107c257600080fd5b506103cb6129fb565b6005805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561086f5780601f106108445761010080835404028352916020019161086f565b820191906000526020600020905b81548152906001019060200180831161085257829003601f168201915b505050505081565b6009546dffffffffffffffffffffffffffff808216926e0100000000000000000000000000009092041690565b60006108b1338484612b30565b5060015b92915050565b6007546001600160a01b031681565b60005481565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146109215760405162461bcd60e51b815260040161091890613e83565b60405180910390fd5b600780546001600160a01b038087167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316179092556008805492861692909116919091179055815161097c906005906020850190613508565b508051610990906006906020840190613508565b5050505050565b6001600160a01b03831660009081526002602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610a34576001600160a01b0384166000908152600260209081526040808320338452909152902054610a0f9083612b98565b6001600160a01b03851660009081526002602090815260408083203384529091529020555b610a3f848484612bda565b5060019392505050565b600954600090610a80906dffffffffffffffffffffffffffff808216916e010000000000000000000000000000900416858561153d565b9392505050565b600080600a54600114610aac5760405162461bcd60e51b815260040161091890613c00565b6000600a8190556007546008546040516370a0823160e01b81526001600160a01b0392831693919092169183906370a0823190610aed903090600401613ab1565b60206040518083038186803b158015610b0557600080fd5b505afa158015610b19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3d91906138f2565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610b6d9190613ab1565b60206040518083038186803b158015610b8557600080fd5b505afa158015610b99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbd91906138f2565b30600090815260016020908152604080832054905193945092479291606091610bee9133918f918f91899101613ac5565b6040516020818303038152906040529050610c07613586565b610c1388600284612c7e565b608086015260408501526020840152825260608201526001600160a01b038d8116908a161415610c5157610c47858261293b565b909b509250610c8d565b876001600160a01b03168d6001600160a01b03161415610c7557610c47858261274e565b60405162461bcd60e51b815260040161091890613dde565b50610ca49050610c9d8347612b98565b3490612b98565b975060008911610cc65760405162461bcd60e51b815260040161091890613e15565b610cd03084612db8565b610cdb8b8b8b612e4e565b8015610db5576040517f80feb3980000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906380feb39890610d46908990600401613ab1565b60206040518083038186803b158015610d5e57600080fd5b505afa158015610d72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9691906138b7565b15610daa57610da58782612fb9565b610db5565b610db5878783613073565b6040516370a0823160e01b81526001600160a01b038816906370a0823190610de1903090600401613ab1565b60206040518083038186803b158015610df957600080fd5b505afa158015610e0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3191906138f2565b6040516370a0823160e01b81529095506001600160a01b038716906370a0823190610e60903090600401613ab1565b60206040518083038186803b158015610e7857600080fd5b505afa158015610e8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb091906138f2565b9350610ebc8585613152565b8715610ecc57610ecc3389613258565b896001600160a01b0316336001600160a01b03167f3dd1df88dc92e2788892542d81f999d720a44b4c127065d45c128f4f59fdc3738d8c604051610f11929190613b43565b60405180910390a3505050505050506001600a819055509250929050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b6305f5e10081565b60035481565b6009546000906108b5906dffffffffffffffffffffffffffff808216916e010000000000000000000000000000900416845b6000805480610fb157670de0b6b3a76400009150611059565b6000610fce84606001516305f5e100612b9890919063ffffffff16565b90506000610ff76305f5e100610ff18760000151896132e590919063ffffffff16565b906132e5565b9050600061101683610ff188602001518b6132e590919063ffffffff16565b90506110538361104d886020015161104d8861104d61103e888a61331f90919063ffffffff16565b670de0b6b3a7640000906132e5565b90613344565b94505050505b509392505050565b670de0b6b3a764000081565b6000806110db61108e84608001516305f5e100612b9890919063ffffffff16565b61104d6110ac86606001516305f5e100612b9890919063ffffffff16565b61104d876020015161104d6305f5e100610ff16305f5e100610ff18d600001518f6132e590919063ffffffff16565b9150826080015160001461110b576111086305f5e10061104d8560800151856132e590919063ffffffff16565b90505b9250929050565b60008061112b8461104d88670de0b6b3a76400006132e5565b9050600061115a6305f5e100610ff18660000151610ff1670de0b6b3a76400008b6132e590919063ffffffff16565b905061119561118e61117d86606001516305f5e10061331f90919063ffffffff16565b602087015161104d9081868b613344565b839061331f565b979650505050505050565b600080600a546001146111c55760405162461bcd60e51b815260040161091890613c00565b6000600a8190556007546008546001600160a01b0391821692911690806111ea610877565b915091506000846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161121c9190613ab1565b60206040518083038186803b15801561123457600080fd5b505afa158015611248573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126c91906138f2565b90506000846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161129c9190613ab1565b60206040518083038186803b1580156112b457600080fd5b505afa1580156112c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ec91906138f2565b9050600061130a836dffffffffffffffffffffffffffff8716612b98565b90506000611328836dffffffffffffffffffffffffffff8716612b98565b905060004790506060338d85856040516020016113489493929190613b1a565b6040516020818303038152906040529050611361613586565b61136d8a600184612c7e565b6080860152604085015260208401528252606082015260006113a36dffffffffffffffffffffffffffff808c16908b1684610f98565b9050600054600014156113e0576113ca633b9aca006113c488888587611112565b90612b98565b9d506113db6000633b9aca00613386565b6113ef565b6113ec86868385611112565b9d505b506114019150610c9d90508247612b98565b995060008b116114235760405162461bcd60e51b815260040161091890613e4c565b61142d8c8c613386565b6114378585613152565b891561144757611447338b613258565b336001600160a01b03167f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f8484604051611482929190613fdd565b60405180910390a25050505050505050506001600a81905550915091565b60016020526000908152604090205481565b60046020526000908152604090205481565b6006805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561086f5780601f106108445761010080835404028352916020019161086f565b600080548061155657670de0b6b3a7640000915061158a565b600061156286866132e5565b9050600061157088866132e5565b90506115858561104d858161103e878761331f565b935050505b50949350505050565b6000806115fa6305f5e10061104d6305f5e10061104d876000015161104d6115cc8a608001516305f5e100612b9890919063ffffffff16565b610ff16115ea8c606001516305f5e100612b9890919063ffffffff16565b60208d0151610ff1908f906132e5565b9150826080015160001461110b576111086305f5e10061104d8560800151876132e590919063ffffffff16565b60008060006116346135b5565b600a546001146116565760405162461bcd60e51b815260040161091890613c00565b6000600a8190556007546008546040516370a0823160e01b81526001600160a01b0392831693919092169183906370a0823190611697903090600401613ab1565b60206040518083038186803b1580156116af57600080fd5b505afa1580156116c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e791906138f2565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016117179190613ab1565b60206040518083038186803b15801561172f57600080fd5b505afa158015611743573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061176791906138f2565b905047600080611775610877565b91509150856001600160a01b03168d6001600160a01b031614156117b4576117ad856dffffffffffffffffffffffffffff8416612b98565b9a506117e8565b866001600160a01b03168d6001600160a01b03161415610c75576117ad846dffffffffffffffffffffffffffff8316612b98565b60008b116118085760405162461bcd60e51b815260040161091890613f85565b6060338e8e8e6040516020016118219493929190613ac5565b604051602081830303815290604052905061183a613586565b61184688600384612c7e565b608086015260408501526020840152825260608201526001600160a01b038f811690891614156118bc5761187a8d82611593565b8b526dffffffffffffffffffffffffffff8581166020808e01919091528301518351929e506118b292909161104d91908716906132e5565b60408b0152611927565b886001600160a01b03168f6001600160a01b03161415611927576118e08d82612874565b8b5260208201518251919d5061190b9161104d906dffffffffffffffffffffffffffff8716906132e5565b60208b01526dffffffffffffffffffffffffffff841660408b01525b611934610c9d8647612b98565b9a5061196a846dffffffffffffffffffffffffffff16846dffffffffffffffffffffffffffff168360000151846020015161153d565b60608b015250505050506001600160a01b03848116908a16148015906119a25750826001600160a01b0316896001600160a01b031614155b6119be5760405162461bcd60e51b815260040161091890613cdc565b6119c98a8a89612e4e565b845115611ab9576040517f80feb3980000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906380feb39890611a35908690600401613ab1565b60206040518083038186803b158015611a4d57600080fd5b505afa158015611a61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8591906138b7565b15611aa157611a9c848660005b6020020151612fb9565b611ab9565b611ab484848760005b6020020151613073565b600085525b6040516370a0823160e01b81526001600160a01b038516906370a0823190611ae5903090600401613ab1565b60206040518083038186803b158015611afd57600080fd5b505afa158015611b11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3591906138f2565b6040516370a0823160e01b81529092506001600160a01b038416906370a0823190611b64903090600401613ab1565b60206040518083038186803b158015611b7c57600080fd5b505afa158015611b90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bb491906138f2565b9050611bc08282613152565b8515611bd057611bd03387613258565b886001600160a01b0316336001600160a01b03167f053d794b2310b8d186a24ae24a65ee066983a52a6efa6bd3df09a7601a3cb4f38a8a8e604051611c1793929190613feb565b60405180910390a350506001600a555093969295509093509150565b6000806000611c406135b5565b600a54600114611c625760405162461bcd60e51b815260040161091890613c00565b6000600a556007546008546001600160a01b039182169116611c82613586565b6040514790606090611c9e9033908e908e908e90602001613aef565b6040516020818303038152906040529050611cbb84600483612c7e565b60808801526040870152602086015284526060840152611cde610c9d8347612b98565b965050506000836001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611d109190613ab1565b60206040518083038186803b158015611d2857600080fd5b505afa158015611d3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d6091906138f2565b90506000836001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611d909190613ab1565b60206040518083038186803b158015611da857600080fd5b505afa158015611dbc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de091906138f2565b9050600080611ded610877565b91509150856001600160a01b03168e6001600160a01b03161415611e6957611e25846dffffffffffffffffffffffffffff8416612b98565b6dffffffffffffffffffffffffffff8381166020808c01919091528701518751929d50611e5b92909161104d91908516906132e5565b8860025b6020020152611ee4565b866001600160a01b03168e6001600160a01b03161415610c7557611e9d836dffffffffffffffffffffffffffff8316612b98565b60208601518651919c50611ec69161104d906dffffffffffffffffffffffffffff8516906132e5565b60208901526dffffffffffffffffffffffffffff8216886002611e5f565b60008b11611f045760405162461bcd60e51b815260040161091890613f85565b611f38826dffffffffffffffffffffffffffff16826dffffffffffffffffffffffffffff168760000151886020015161153d565b60608901525060009250829150506001600160a01b03848116908d161415611f8a57611f648b8461106d565b87529150611f728983612b98565b90508015611f8557611f85858b83612e4e565b611fcf565b846001600160a01b03168c6001600160a01b03161415611fcf57611fae8b846124f2565b87529150611fbc8983612b98565b90508015611fcf57611fcf848b83612e4e565b88821115611fef5760405162461bcd60e51b815260040161091890613ca5565b6000821161200f5760405162461bcd60e51b815260040161091890613d70565b5050826001600160a01b0316886001600160a01b0316141580156120455750816001600160a01b0316886001600160a01b031614155b6120615760405162461bcd60e51b815260040161091890613cdc565b88955061206f8a8988612e4e565b835115612153576040517f80feb3980000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906380feb398906120db908590600401613ab1565b60206040518083038186803b1580156120f357600080fd5b505afa158015612107573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061212b91906138b7565b156121415761213c83856000611a92565b612153565b61214e8383866000611aaa565b600084525b6040516370a0823160e01b81526000906001600160a01b038516906370a0823190612182903090600401613ab1565b60206040518083038186803b15801561219a57600080fd5b505afa1580156121ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d291906138f2565b90506000836001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016122029190613ab1565b60206040518083038186803b15801561221a57600080fd5b505afa15801561222e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225291906138f2565b905061225e8282613152565b861561226e5761226e3388613258565b5050876001600160a01b0316336001600160a01b03167f053d794b2310b8d186a24ae24a65ee066983a52a6efa6bd3df09a7601a3cb4f389898e6040516122b793929190613feb565b60405180910390a35050506001600a8190555093509350935093565b6040518060400160405280601081526020017f436f46695820506f6f6c20546f6b656e0000000000000000000000000000000081525081565b60006108b1338484612bda565b60008061232583610f66565b905061233385858386611112565b95945050505050565b600080548061235557670de0b6b3a76400009150611059565b6000610fce84606001516305f5e10061331f90919063ffffffff16565b633b9aca0081565b600a5460011461239c5760405162461bcd60e51b815260040161091890613c00565b6000600a556007546008546009546040516370a0823160e01b81526001600160a01b039384169390921691612451918491869161244c916dffffffffffffffffffffffffffff9091169084906370a08231906123fc903090600401613ab1565b60206040518083038186803b15801561241457600080fd5b505afa158015612428573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c491906138f2565b612e4e565b6124b2818461244c6009600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16856001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016123fc9190613ab1565b50506001600a5550565b6009546000906108b5906dffffffffffffffffffffffffffff808216916e0100000000000000000000000000009004168461233c565b60008061254961251384608001516305f5e100612b9890919063ffffffff16565b61104d6305f5e10061104d876000015161104d6305f5e100610ff16115ea8c606001516305f5e10061331f90919063ffffffff16565b9150826080015160001461110b576111086305f5e10061104d61257d86606001516305f5e10061331f90919063ffffffff16565b61104d876020015161104d8960800151610ff16305f5e100610ff18d600001518d6132e590919063ffffffff16565b7f000000000000000000000000000000000000000000000000000000000000000081565b6008546001600160a01b031681565b428410156125ff5760405162461bcd60e51b815260040161091890613da7565b6003546001600160a01b03881660009081526004602090815260408083208054600181019091559051929392612660927f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9928d928d928d92918d9101613b9b565b60405160208183030381529060405280519060200120604051602001612687929190613a7b565b6040516020818303038152906040528051906020012090506000600182868686604051600081526020016040526040516126c49493929190613bcf565b6020604051602081039080840390855afa1580156126e6573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580159061271c5750886001600160a01b0316816001600160a01b0316145b6127385760405162461bcd60e51b815260040161091890613c37565b612743898989612b30565b505050505050505050565b60095460009081908190612788906dffffffffffffffffffffffffffff808216916e0100000000000000000000000000009004168661233c565b905060006127d96127aa86608001516305f5e100612b9890919063ffffffff16565b610ff16127c888606001516305f5e100612b9890919063ffffffff16565b6020890151610ff190818c896132e5565b905061280e6305f5e10061104d6305f5e10061104d896000015161104d670de0b6b3a76400008861334490919063ffffffff16565b9350846080015160001461284e5761284b6305f5e10061104d670de0b6b3a764000061104d8960800151610ff1888d6132e590919063ffffffff16565b92505b50509250929050565b600260209081526000928352604080842090915290825290205481565b6000806128d86305f5e10061104d61289d86606001516305f5e10061331f90919063ffffffff16565b61104d876020015161104d6128c38a608001516305f5e100612b9890919063ffffffff16565b8a51610ff1906305f5e1009082908f906132e5565b9150826080015160001461110b576111086305f5e10061104d61290c86606001516305f5e10061331f90919063ffffffff16565b61104d876020015161104d8960800151610ff16305f5e100610ff18d600001518f6132e590919063ffffffff16565b60095460009081908190612975906dffffffffffffffffffffffffffff808216916e0100000000000000000000000000009004168661233c565b90506129b36305f5e10061104d670de0b6b3a764000061104d6129a989608001516305f5e100612b9890919063ffffffff16565b610ff18b886132e5565b925083608001516000146129f3576129f06305f5e10061104d670de0b6b3a764000061104d8860800151610ff1878c6132e590919063ffffffff16565b91505b509250929050565b600a54600114612a1d5760405162461bcd60e51b815260040161091890613c00565b6000600a556007546040516370a0823160e01b8152612b29916001600160a01b0316906370a0823190612a54903090600401613ab1565b60206040518083038186803b158015612a6c57600080fd5b505afa158015612a80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aa491906138f2565b6008546040516370a0823160e01b81526001600160a01b03909116906370a0823190612ad4903090600401613ab1565b60206040518083038186803b158015612aec57600080fd5b505afa158015612b00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b2491906138f2565b613152565b6001600a55565b6001600160a01b0380841660008181526002602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590612b8b908590613b92565b60405180910390a3505050565b6000610a8083836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613407565b6001600160a01b038316600090815260016020526040902054612bfd9082612b98565b6001600160a01b038085166000908152600160205260408082209390935590841681522054612c2c908261331f565b6001600160a01b0380841660008181526001602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612b8b908590613b92565b60008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633018205f6040518163ffffffff1660e01b815260040160206040518083038186803b158015612cdf57600080fd5b505afa158015612cf3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d1791906136bc565b6001600160a01b0316638dba9329348a8a6004811115612d3357fe5b8a6040518563ffffffff1660e01b8152600401612d5293929190613b5c565b60a0604051808303818588803b158015612d6b57600080fd5b505af1158015612d7f573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190612da491906139f4565b939c929b5090995097509095509350505050565b6001600160a01b038216600090815260016020526040902054612ddb9082612b98565b6001600160a01b03831660009081526001602052604081209190915554612e029082612b98565b60009081556040516001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612e42908590613b92565b60405180910390a35050565b604080518082018252601981527f7472616e7366657228616464726573732c75696e743235362900000000000000602090910152516000906060906001600160a01b038616907fa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b90612ec69087908790602401613b43565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051612f319190613a5f565b6000604051808303816000865af19150503d8060008114612f6e576040519150601f19603f3d011682016040523d82523d6000602084013e612f73565b606091505b5091509150818015612f9d575080511580612f9d575080806020019051810190612f9d91906138b7565b6109905760405162461bcd60e51b815260040161091890613f17565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e8a353926040518163ffffffff1660e01b815260040160206040518083038186803b15801561301457600080fd5b505afa158015613028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304c91906136bc565b90506001600160a01b038116613062575061306f565b61306d838284613433565b505b5050565b6040517f72b8cbcc0000000000000000000000000000000000000000000000000000000081526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906372b8cbcc906130db908690600401613ab1565b60206040518083038186803b1580156130f357600080fd5b505afa158015613107573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061312b91906136bc565b90506001600160a01b038116613141575061306d565b61314c848284613433565b50505050565b6dffffffffffffffffffffffffffff821180159061317e57506dffffffffffffffffffffffffffff8111155b61319a5760405162461bcd60e51b815260040161091890613f4e565b600980547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff848116919091177fffffffff0000000000000000000000000000ffffffffffffffffffffffffffff166e010000000000000000000000000000848316810291909117928390556040517f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad19361324c93818116939091041690613fbc565b60405180910390a15050565b604080516000808252602082019092526001600160a01b0384169083906040516132829190613a5f565b60006040518083038185875af1925050503d80600081146132bf576040519150601f19603f3d011682016040523d82523d6000602084013e6132c4565b606091505b505090508061306d5760405162461bcd60e51b815260040161091890613eba565b6000826132f4575060006108b5565b8282028284828161330157fe5b0414610a805760405162461bcd60e51b815260040161091890613d13565b600082820183811015610a805760405162461bcd60e51b815260040161091890613c6e565b6000610a8083836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506134d1565b600054613393908261331f565b60009081556001600160a01b0383168152600160205260409020546133b8908261331f565b6001600160a01b0383166000818152600160205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612e42908590613b92565b6000818484111561342b5760405162461bcd60e51b81526004016109189190613bed565b505050900390565b6040516370a0823160e01b81526000906001600160a01b038516906370a0823190613462903090600401613ab1565b60206040518083038186803b15801561347a57600080fd5b505afa15801561348e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134b291906138f2565b9050808211156134c0578091505b811561314c5761314c848484612e4e565b600081836134f25760405162461bcd60e51b81526004016109189190613bed565b5060008385816134fe57fe5b0495945050505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061354957805160ff1916838001178555613576565b82800160010185558215613576579182015b8281111561357657825182559160200191906001019061355b565b506135829291506135d3565b5090565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60405180608001604052806004906020820280368337509192915050565b5b8082111561358257600081556001016135d4565b600082601f8301126135f8578081fd5b813567ffffffffffffffff81111561360e578182fd5b6136216020601f19601f84011601614062565b915080825283602082850101111561363857600080fd5b8060208401602084013760009082016020015292915050565b600060a08284031215613662578081fd5b61366c60a0614062565b9050813581526020820135602082015260408201356040820152606082013560608201526080820135608082015292915050565b6000602082840312156136b1578081fd5b8135610a80816140b5565b6000602082840312156136cd578081fd5b8151610a80816140b5565b600080604083850312156136ea578081fd5b82356136f5816140b5565b91506020830135613705816140b5565b809150509250929050565b60008060008060808587031215613725578182fd5b8435613730816140b5565b93506020850135613740816140b5565b9250604085013567ffffffffffffffff8082111561375c578384fd5b613768888389016135e8565b9350606087013591508082111561377d578283fd5b5061378a878288016135e8565b91505092959194509250565b6000806000606084860312156137aa578283fd5b83356137b5816140b5565b925060208401356137c5816140b5565b929592945050506040919091013590565b600080600080600080600060e0888a0312156137f0578283fd5b87356137fb816140b5565b9650602088013561380b816140b5565b95506040880135945060608801359350608088013560ff8116811461382e578384fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561385d578182fd5b8235613868816140b5565b946020939093013593505050565b60008060006060848603121561388a578283fd5b8335613895816140b5565b92506020840135915060408401356138ac816140b5565b809150509250925092565b6000602082840312156138c8578081fd5b81518015158114610a80578182fd5b600060a082840312156138e8578081fd5b610a808383613651565b600060208284031215613903578081fd5b5051919050565b60008060c0838503121561391c578182fd5b823591506111088460208501613651565b6000806040838503121561393f578182fd5b50508035926020909101359150565b600080600060e08486031215613962578081fd5b833592506020840135915061397a8560408601613651565b90509250925092565b6000806000806101008587031215613999578182fd5b8435935060208501359250604085013591506139b88660608701613651565b905092959194509250565b600080600080608085870312156139d8578182fd5b5050823594602084013594506040840135936060013592509050565b600080600080600060a08688031215613a0b578283fd5b5050835160208501516040860151606087015160809097015192989197509594509092509050565b60008151808452613a4b816020860160208601614089565b601f01601f19169290920160200192915050565b60008251613a71818460208701614089565b9190910192915050565b7f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b6001600160a01b03948516815292841660208401526040830191909152909116606082015260800190565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6001600160a01b03929092168252602082015260400190565b60006001600160a01b038516825260ff84166020830152606060408301526123336060830184613a33565b901515815260200190565b90815260200190565b9586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b93845260ff9290921660208401526040830152606082015260800190565b600060208252610a806020830184613a33565b6020808252600d908201527f43506169723a204c4f434b454400000000000000000000000000000000000000604082015260600190565b60208082526019908201527f4345524332303a20494e56414c49445f5349474e415455524500000000000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601c908201527f43506169723a20696e73756666696369656e7420616d6f756e74496e00000000604082015260600190565b60208082526011908201527f43506169723a20494e56414c49445f544f000000000000000000000000000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60408201527f7700000000000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252601c908201527f43506169723a2077726f6e6720616d6f756e74496e206e656564656400000000604082015260600190565b6020808252600f908201527f4345524332303a20455850495245440000000000000000000000000000000000604082015260600190565b60208082526015908201527f43506169723a2077726f6e67206f7574546f6b656e0000000000000000000000604082015260600190565b6020808252601d908201527f43506169723a2053484f52545f4c49515549444954595f4255524e4544000000604082015260600190565b6020808252601d908201527f43506169723a2053484f52545f4c49515549444954595f4d494e544544000000604082015260600190565b60208082526010908201527f43506169723a20464f5242494444454e00000000000000000000000000000000604082015260600190565b60208082526023908201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960408201527f4c45440000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526016908201527f43506169723a205452414e534645525f4641494c454400000000000000000000604082015260600190565b6020808252600f908201527f43506169723a204f564552464c4f570000000000000000000000000000000000604082015260600190565b60208082526015908201527f43506169723a2077726f6e6720616d6f756e74496e0000000000000000000000604082015260600190565b6dffffffffffffffffffffffffffff92831681529116602082015260400190565b918252602082015260400190565b92835260208301919091526001600160a01b0316604082015260600190565b600060e08201905085825260208581840152846040840152606083018460005b60048110156140475781518352918301919083019060010161402a565b5050505095945050505050565b60ff91909116815260200190565b60405181810167ffffffffffffffff8111828210171561408157600080fd5b604052919050565b60005b838110156140a457818101518382015260200161408c565b8381111561314c5750506000910152565b6001600160a01b03811681146140ca57600080fd5b5056fea26469706673582212204d9c04fecc367b0b983af1eb4467f748ca149b973eebf1723301659a88c0b77264736f6c634300060c0033

Deployed Bytecode

0x6080604052600436106102e05760003560e01c806395d89b4111610184578063bc25cf77116100d6578063d505accf1161008a578063e5eac39011610064578063e5eac39014610776578063eb77289914610796578063fff6cae9146107b6576102e7565b8063d505accf14610716578063dd2e0a3114610736578063dd62ed3e14610756576102e7565b8063bf36aac2116100bb578063bf36aac2146106cc578063c45a0155146106ec578063d21220a714610701576102e7565b8063bc25cf771461068c578063be5b32f8146106ac576102e7565b8063a661dbda11610138578063b2874f8711610112578063b2874f8714610637578063b72bda4a14610657578063ba9a7a5614610677576102e7565b8063a661dbda14610602578063a9059cbb14610617578063aaf07e9214610465576102e7565b80639c673c52116101695780639c673c52146105ac5780639f44296a146105cc578063a12db6cc146105ef576102e7565b806395d89b411461057757806399f45e481461058c576102e7565b8063313ce5671161023d5780634f6ec2dd116101f15780636a627842116101cb5780636a6278421461052457806370a08231146105375780637ecebe0014610557576102e7565b80634f6ec2dd146104cf5780635ad6bd30146104e4578063663eda1f14610504576102e7565b80633644e515116102225780633644e5151461047a57806339818b661461048f57806349a23da0146104af576102e7565b8063313ce567146104435780633298613114610465576102e7565b80632016a0d21161029457806324334be81161027957806324334be8146103ed57806327fc84a31461040d57806330adf81f1461042e576102e7565b80632016a0d2146103ab57806323b872dd146103cd576102e7565b8063095ea7b3116102c5578063095ea7b31461033a5780630dfe16811461036757806318160ddd14610389576102e7565b806306fdde03146102ec5780630902f1ac14610317576102e7565b366102e757005b600080fd5b3480156102f857600080fd5b506103016107cb565b60405161030e9190613bed565b60405180910390f35b34801561032357600080fd5b5061032c610877565b60405161030e929190613fbc565b34801561034657600080fd5b5061035a61035536600461384b565b6108a4565b60405161030e9190613b87565b34801561037357600080fd5b5061037c6108bb565b60405161030e9190613ab1565b34801561039557600080fd5b5061039e6108ca565b60405161030e9190613b92565b3480156103b757600080fd5b506103cb6103c6366004613710565b6108d0565b005b3480156103d957600080fd5b5061035a6103e8366004613796565b610997565b3480156103f957600080fd5b5061039e61040836600461392d565b610a49565b61042061041b3660046136d8565b610a87565b60405161030e929190613fdd565b34801561043a57600080fd5b5061039e610f2f565b34801561044f57600080fd5b50610458610f53565b60405161030e9190614054565b34801561047157600080fd5b5061039e610f58565b34801561048657600080fd5b5061039e610f60565b34801561049b57600080fd5b5061039e6104aa3660046138d7565b610f66565b3480156104bb57600080fd5b5061039e6104ca36600461394e565b610f98565b3480156104db57600080fd5b5061039e611061565b3480156104f057600080fd5b506104206104ff36600461390a565b61106d565b34801561051057600080fd5b5061039e61051f366004613983565b611112565b6104206105323660046136a0565b6111a0565b34801561054357600080fd5b5061039e6105523660046136a0565b6114a0565b34801561056357600080fd5b5061039e6105723660046136a0565b6114b2565b34801561058357600080fd5b506103016114c4565b34801561059857600080fd5b5061039e6105a73660046139c3565b61153d565b3480156105b857600080fd5b506104206105c736600461390a565b611593565b6105df6105da3660046136d8565b611627565b60405161030e949392919061400a565b6105df6105fd366004613876565b611c33565b34801561060e57600080fd5b506103016122d3565b34801561062357600080fd5b5061035a61063236600461384b565b61230c565b34801561064357600080fd5b5061039e61065236600461394e565b612319565b34801561066357600080fd5b5061039e61067236600461394e565b61233c565b34801561068357600080fd5b5061039e612372565b34801561069857600080fd5b506103cb6106a73660046136a0565b61237a565b3480156106b857600080fd5b5061039e6106c73660046138d7565b6124bc565b3480156106d857600080fd5b506104206106e736600461390a565b6124f2565b3480156106f857600080fd5b5061037c6125ac565b34801561070d57600080fd5b5061037c6125d0565b34801561072257600080fd5b506103cb6107313660046137d6565b6125df565b34801561074257600080fd5b5061042061075136600461390a565b61274e565b34801561076257600080fd5b5061039e6107713660046136d8565b612857565b34801561078257600080fd5b5061042061079136600461390a565b612874565b3480156107a257600080fd5b506104206107b136600461390a565b61293b565b3480156107c257600080fd5b506103cb6129fb565b6005805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561086f5780601f106108445761010080835404028352916020019161086f565b820191906000526020600020905b81548152906001019060200180831161085257829003601f168201915b505050505081565b6009546dffffffffffffffffffffffffffff808216926e0100000000000000000000000000009092041690565b60006108b1338484612b30565b5060015b92915050565b6007546001600160a01b031681565b60005481565b336001600160a01b037f00000000000000000000000066c64ecc3a6014733325a8f2ebee46b4ca3ed55016146109215760405162461bcd60e51b815260040161091890613e83565b60405180910390fd5b600780546001600160a01b038087167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316179092556008805492861692909116919091179055815161097c906005906020850190613508565b508051610990906006906020840190613508565b5050505050565b6001600160a01b03831660009081526002602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610a34576001600160a01b0384166000908152600260209081526040808320338452909152902054610a0f9083612b98565b6001600160a01b03851660009081526002602090815260408083203384529091529020555b610a3f848484612bda565b5060019392505050565b600954600090610a80906dffffffffffffffffffffffffffff808216916e010000000000000000000000000000900416858561153d565b9392505050565b600080600a54600114610aac5760405162461bcd60e51b815260040161091890613c00565b6000600a8190556007546008546040516370a0823160e01b81526001600160a01b0392831693919092169183906370a0823190610aed903090600401613ab1565b60206040518083038186803b158015610b0557600080fd5b505afa158015610b19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3d91906138f2565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610b6d9190613ab1565b60206040518083038186803b158015610b8557600080fd5b505afa158015610b99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbd91906138f2565b30600090815260016020908152604080832054905193945092479291606091610bee9133918f918f91899101613ac5565b6040516020818303038152906040529050610c07613586565b610c1388600284612c7e565b608086015260408501526020840152825260608201526001600160a01b038d8116908a161415610c5157610c47858261293b565b909b509250610c8d565b876001600160a01b03168d6001600160a01b03161415610c7557610c47858261274e565b60405162461bcd60e51b815260040161091890613dde565b50610ca49050610c9d8347612b98565b3490612b98565b975060008911610cc65760405162461bcd60e51b815260040161091890613e15565b610cd03084612db8565b610cdb8b8b8b612e4e565b8015610db5576040517f80feb3980000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000066c64ecc3a6014733325a8f2ebee46b4ca3ed55016906380feb39890610d46908990600401613ab1565b60206040518083038186803b158015610d5e57600080fd5b505afa158015610d72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9691906138b7565b15610daa57610da58782612fb9565b610db5565b610db5878783613073565b6040516370a0823160e01b81526001600160a01b038816906370a0823190610de1903090600401613ab1565b60206040518083038186803b158015610df957600080fd5b505afa158015610e0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3191906138f2565b6040516370a0823160e01b81529095506001600160a01b038716906370a0823190610e60903090600401613ab1565b60206040518083038186803b158015610e7857600080fd5b505afa158015610e8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb091906138f2565b9350610ebc8585613152565b8715610ecc57610ecc3389613258565b896001600160a01b0316336001600160a01b03167f3dd1df88dc92e2788892542d81f999d720a44b4c127065d45c128f4f59fdc3738d8c604051610f11929190613b43565b60405180910390a3505050505050506001600a819055509250929050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b6305f5e10081565b60035481565b6009546000906108b5906dffffffffffffffffffffffffffff808216916e010000000000000000000000000000900416845b6000805480610fb157670de0b6b3a76400009150611059565b6000610fce84606001516305f5e100612b9890919063ffffffff16565b90506000610ff76305f5e100610ff18760000151896132e590919063ffffffff16565b906132e5565b9050600061101683610ff188602001518b6132e590919063ffffffff16565b90506110538361104d886020015161104d8861104d61103e888a61331f90919063ffffffff16565b670de0b6b3a7640000906132e5565b90613344565b94505050505b509392505050565b670de0b6b3a764000081565b6000806110db61108e84608001516305f5e100612b9890919063ffffffff16565b61104d6110ac86606001516305f5e100612b9890919063ffffffff16565b61104d876020015161104d6305f5e100610ff16305f5e100610ff18d600001518f6132e590919063ffffffff16565b9150826080015160001461110b576111086305f5e10061104d8560800151856132e590919063ffffffff16565b90505b9250929050565b60008061112b8461104d88670de0b6b3a76400006132e5565b9050600061115a6305f5e100610ff18660000151610ff1670de0b6b3a76400008b6132e590919063ffffffff16565b905061119561118e61117d86606001516305f5e10061331f90919063ffffffff16565b602087015161104d9081868b613344565b839061331f565b979650505050505050565b600080600a546001146111c55760405162461bcd60e51b815260040161091890613c00565b6000600a8190556007546008546001600160a01b0391821692911690806111ea610877565b915091506000846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161121c9190613ab1565b60206040518083038186803b15801561123457600080fd5b505afa158015611248573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126c91906138f2565b90506000846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161129c9190613ab1565b60206040518083038186803b1580156112b457600080fd5b505afa1580156112c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ec91906138f2565b9050600061130a836dffffffffffffffffffffffffffff8716612b98565b90506000611328836dffffffffffffffffffffffffffff8716612b98565b905060004790506060338d85856040516020016113489493929190613b1a565b6040516020818303038152906040529050611361613586565b61136d8a600184612c7e565b6080860152604085015260208401528252606082015260006113a36dffffffffffffffffffffffffffff808c16908b1684610f98565b9050600054600014156113e0576113ca633b9aca006113c488888587611112565b90612b98565b9d506113db6000633b9aca00613386565b6113ef565b6113ec86868385611112565b9d505b506114019150610c9d90508247612b98565b995060008b116114235760405162461bcd60e51b815260040161091890613e4c565b61142d8c8c613386565b6114378585613152565b891561144757611447338b613258565b336001600160a01b03167f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f8484604051611482929190613fdd565b60405180910390a25050505050505050506001600a81905550915091565b60016020526000908152604090205481565b60046020526000908152604090205481565b6006805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561086f5780601f106108445761010080835404028352916020019161086f565b600080548061155657670de0b6b3a7640000915061158a565b600061156286866132e5565b9050600061157088866132e5565b90506115858561104d858161103e878761331f565b935050505b50949350505050565b6000806115fa6305f5e10061104d6305f5e10061104d876000015161104d6115cc8a608001516305f5e100612b9890919063ffffffff16565b610ff16115ea8c606001516305f5e100612b9890919063ffffffff16565b60208d0151610ff1908f906132e5565b9150826080015160001461110b576111086305f5e10061104d8560800151876132e590919063ffffffff16565b60008060006116346135b5565b600a546001146116565760405162461bcd60e51b815260040161091890613c00565b6000600a8190556007546008546040516370a0823160e01b81526001600160a01b0392831693919092169183906370a0823190611697903090600401613ab1565b60206040518083038186803b1580156116af57600080fd5b505afa1580156116c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e791906138f2565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016117179190613ab1565b60206040518083038186803b15801561172f57600080fd5b505afa158015611743573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061176791906138f2565b905047600080611775610877565b91509150856001600160a01b03168d6001600160a01b031614156117b4576117ad856dffffffffffffffffffffffffffff8416612b98565b9a506117e8565b866001600160a01b03168d6001600160a01b03161415610c75576117ad846dffffffffffffffffffffffffffff8316612b98565b60008b116118085760405162461bcd60e51b815260040161091890613f85565b6060338e8e8e6040516020016118219493929190613ac5565b604051602081830303815290604052905061183a613586565b61184688600384612c7e565b608086015260408501526020840152825260608201526001600160a01b038f811690891614156118bc5761187a8d82611593565b8b526dffffffffffffffffffffffffffff8581166020808e01919091528301518351929e506118b292909161104d91908716906132e5565b60408b0152611927565b886001600160a01b03168f6001600160a01b03161415611927576118e08d82612874565b8b5260208201518251919d5061190b9161104d906dffffffffffffffffffffffffffff8716906132e5565b60208b01526dffffffffffffffffffffffffffff841660408b01525b611934610c9d8647612b98565b9a5061196a846dffffffffffffffffffffffffffff16846dffffffffffffffffffffffffffff168360000151846020015161153d565b60608b015250505050506001600160a01b03848116908a16148015906119a25750826001600160a01b0316896001600160a01b031614155b6119be5760405162461bcd60e51b815260040161091890613cdc565b6119c98a8a89612e4e565b845115611ab9576040517f80feb3980000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000066c64ecc3a6014733325a8f2ebee46b4ca3ed55016906380feb39890611a35908690600401613ab1565b60206040518083038186803b158015611a4d57600080fd5b505afa158015611a61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8591906138b7565b15611aa157611a9c848660005b6020020151612fb9565b611ab9565b611ab484848760005b6020020151613073565b600085525b6040516370a0823160e01b81526001600160a01b038516906370a0823190611ae5903090600401613ab1565b60206040518083038186803b158015611afd57600080fd5b505afa158015611b11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3591906138f2565b6040516370a0823160e01b81529092506001600160a01b038416906370a0823190611b64903090600401613ab1565b60206040518083038186803b158015611b7c57600080fd5b505afa158015611b90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bb491906138f2565b9050611bc08282613152565b8515611bd057611bd03387613258565b886001600160a01b0316336001600160a01b03167f053d794b2310b8d186a24ae24a65ee066983a52a6efa6bd3df09a7601a3cb4f38a8a8e604051611c1793929190613feb565b60405180910390a350506001600a555093969295509093509150565b6000806000611c406135b5565b600a54600114611c625760405162461bcd60e51b815260040161091890613c00565b6000600a556007546008546001600160a01b039182169116611c82613586565b6040514790606090611c9e9033908e908e908e90602001613aef565b6040516020818303038152906040529050611cbb84600483612c7e565b60808801526040870152602086015284526060840152611cde610c9d8347612b98565b965050506000836001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611d109190613ab1565b60206040518083038186803b158015611d2857600080fd5b505afa158015611d3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d6091906138f2565b90506000836001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611d909190613ab1565b60206040518083038186803b158015611da857600080fd5b505afa158015611dbc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de091906138f2565b9050600080611ded610877565b91509150856001600160a01b03168e6001600160a01b03161415611e6957611e25846dffffffffffffffffffffffffffff8416612b98565b6dffffffffffffffffffffffffffff8381166020808c01919091528701518751929d50611e5b92909161104d91908516906132e5565b8860025b6020020152611ee4565b866001600160a01b03168e6001600160a01b03161415610c7557611e9d836dffffffffffffffffffffffffffff8316612b98565b60208601518651919c50611ec69161104d906dffffffffffffffffffffffffffff8516906132e5565b60208901526dffffffffffffffffffffffffffff8216886002611e5f565b60008b11611f045760405162461bcd60e51b815260040161091890613f85565b611f38826dffffffffffffffffffffffffffff16826dffffffffffffffffffffffffffff168760000151886020015161153d565b60608901525060009250829150506001600160a01b03848116908d161415611f8a57611f648b8461106d565b87529150611f728983612b98565b90508015611f8557611f85858b83612e4e565b611fcf565b846001600160a01b03168c6001600160a01b03161415611fcf57611fae8b846124f2565b87529150611fbc8983612b98565b90508015611fcf57611fcf848b83612e4e565b88821115611fef5760405162461bcd60e51b815260040161091890613ca5565b6000821161200f5760405162461bcd60e51b815260040161091890613d70565b5050826001600160a01b0316886001600160a01b0316141580156120455750816001600160a01b0316886001600160a01b031614155b6120615760405162461bcd60e51b815260040161091890613cdc565b88955061206f8a8988612e4e565b835115612153576040517f80feb3980000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000066c64ecc3a6014733325a8f2ebee46b4ca3ed55016906380feb398906120db908590600401613ab1565b60206040518083038186803b1580156120f357600080fd5b505afa158015612107573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061212b91906138b7565b156121415761213c83856000611a92565b612153565b61214e8383866000611aaa565b600084525b6040516370a0823160e01b81526000906001600160a01b038516906370a0823190612182903090600401613ab1565b60206040518083038186803b15801561219a57600080fd5b505afa1580156121ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d291906138f2565b90506000836001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016122029190613ab1565b60206040518083038186803b15801561221a57600080fd5b505afa15801561222e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225291906138f2565b905061225e8282613152565b861561226e5761226e3388613258565b5050876001600160a01b0316336001600160a01b03167f053d794b2310b8d186a24ae24a65ee066983a52a6efa6bd3df09a7601a3cb4f389898e6040516122b793929190613feb565b60405180910390a35050506001600a8190555093509350935093565b6040518060400160405280601081526020017f436f46695820506f6f6c20546f6b656e0000000000000000000000000000000081525081565b60006108b1338484612bda565b60008061232583610f66565b905061233385858386611112565b95945050505050565b600080548061235557670de0b6b3a76400009150611059565b6000610fce84606001516305f5e10061331f90919063ffffffff16565b633b9aca0081565b600a5460011461239c5760405162461bcd60e51b815260040161091890613c00565b6000600a556007546008546009546040516370a0823160e01b81526001600160a01b039384169390921691612451918491869161244c916dffffffffffffffffffffffffffff9091169084906370a08231906123fc903090600401613ab1565b60206040518083038186803b15801561241457600080fd5b505afa158015612428573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c491906138f2565b612e4e565b6124b2818461244c6009600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16856001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016123fc9190613ab1565b50506001600a5550565b6009546000906108b5906dffffffffffffffffffffffffffff808216916e0100000000000000000000000000009004168461233c565b60008061254961251384608001516305f5e100612b9890919063ffffffff16565b61104d6305f5e10061104d876000015161104d6305f5e100610ff16115ea8c606001516305f5e10061331f90919063ffffffff16565b9150826080015160001461110b576111086305f5e10061104d61257d86606001516305f5e10061331f90919063ffffffff16565b61104d876020015161104d8960800151610ff16305f5e100610ff18d600001518d6132e590919063ffffffff16565b7f00000000000000000000000066c64ecc3a6014733325a8f2ebee46b4ca3ed55081565b6008546001600160a01b031681565b428410156125ff5760405162461bcd60e51b815260040161091890613da7565b6003546001600160a01b03881660009081526004602090815260408083208054600181019091559051929392612660927f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9928d928d928d92918d9101613b9b565b60405160208183030381529060405280519060200120604051602001612687929190613a7b565b6040516020818303038152906040528051906020012090506000600182868686604051600081526020016040526040516126c49493929190613bcf565b6020604051602081039080840390855afa1580156126e6573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580159061271c5750886001600160a01b0316816001600160a01b0316145b6127385760405162461bcd60e51b815260040161091890613c37565b612743898989612b30565b505050505050505050565b60095460009081908190612788906dffffffffffffffffffffffffffff808216916e0100000000000000000000000000009004168661233c565b905060006127d96127aa86608001516305f5e100612b9890919063ffffffff16565b610ff16127c888606001516305f5e100612b9890919063ffffffff16565b6020890151610ff190818c896132e5565b905061280e6305f5e10061104d6305f5e10061104d896000015161104d670de0b6b3a76400008861334490919063ffffffff16565b9350846080015160001461284e5761284b6305f5e10061104d670de0b6b3a764000061104d8960800151610ff1888d6132e590919063ffffffff16565b92505b50509250929050565b600260209081526000928352604080842090915290825290205481565b6000806128d86305f5e10061104d61289d86606001516305f5e10061331f90919063ffffffff16565b61104d876020015161104d6128c38a608001516305f5e100612b9890919063ffffffff16565b8a51610ff1906305f5e1009082908f906132e5565b9150826080015160001461110b576111086305f5e10061104d61290c86606001516305f5e10061331f90919063ffffffff16565b61104d876020015161104d8960800151610ff16305f5e100610ff18d600001518f6132e590919063ffffffff16565b60095460009081908190612975906dffffffffffffffffffffffffffff808216916e0100000000000000000000000000009004168661233c565b90506129b36305f5e10061104d670de0b6b3a764000061104d6129a989608001516305f5e100612b9890919063ffffffff16565b610ff18b886132e5565b925083608001516000146129f3576129f06305f5e10061104d670de0b6b3a764000061104d8860800151610ff1878c6132e590919063ffffffff16565b91505b509250929050565b600a54600114612a1d5760405162461bcd60e51b815260040161091890613c00565b6000600a556007546040516370a0823160e01b8152612b29916001600160a01b0316906370a0823190612a54903090600401613ab1565b60206040518083038186803b158015612a6c57600080fd5b505afa158015612a80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aa491906138f2565b6008546040516370a0823160e01b81526001600160a01b03909116906370a0823190612ad4903090600401613ab1565b60206040518083038186803b158015612aec57600080fd5b505afa158015612b00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b2491906138f2565b613152565b6001600a55565b6001600160a01b0380841660008181526002602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590612b8b908590613b92565b60405180910390a3505050565b6000610a8083836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613407565b6001600160a01b038316600090815260016020526040902054612bfd9082612b98565b6001600160a01b038085166000908152600160205260408082209390935590841681522054612c2c908261331f565b6001600160a01b0380841660008181526001602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612b8b908590613b92565b60008060008060007f00000000000000000000000066c64ecc3a6014733325a8f2ebee46b4ca3ed5506001600160a01b0316633018205f6040518163ffffffff1660e01b815260040160206040518083038186803b158015612cdf57600080fd5b505afa158015612cf3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d1791906136bc565b6001600160a01b0316638dba9329348a8a6004811115612d3357fe5b8a6040518563ffffffff1660e01b8152600401612d5293929190613b5c565b60a0604051808303818588803b158015612d6b57600080fd5b505af1158015612d7f573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190612da491906139f4565b939c929b5090995097509095509350505050565b6001600160a01b038216600090815260016020526040902054612ddb9082612b98565b6001600160a01b03831660009081526001602052604081209190915554612e029082612b98565b60009081556040516001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612e42908590613b92565b60405180910390a35050565b604080518082018252601981527f7472616e7366657228616464726573732c75696e743235362900000000000000602090910152516000906060906001600160a01b038616907fa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b90612ec69087908790602401613b43565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051612f319190613a5f565b6000604051808303816000865af19150503d8060008114612f6e576040519150601f19603f3d011682016040523d82523d6000602084013e612f73565b606091505b5091509150818015612f9d575080511580612f9d575080806020019051810190612f9d91906138b7565b6109905760405162461bcd60e51b815260040161091890613f17565b60007f00000000000000000000000066c64ecc3a6014733325a8f2ebee46b4ca3ed5506001600160a01b031663e8a353926040518163ffffffff1660e01b815260040160206040518083038186803b15801561301457600080fd5b505afa158015613028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304c91906136bc565b90506001600160a01b038116613062575061306f565b61306d838284613433565b505b5050565b6040517f72b8cbcc0000000000000000000000000000000000000000000000000000000081526000906001600160a01b037f00000000000000000000000066c64ecc3a6014733325a8f2ebee46b4ca3ed55016906372b8cbcc906130db908690600401613ab1565b60206040518083038186803b1580156130f357600080fd5b505afa158015613107573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061312b91906136bc565b90506001600160a01b038116613141575061306d565b61314c848284613433565b50505050565b6dffffffffffffffffffffffffffff821180159061317e57506dffffffffffffffffffffffffffff8111155b61319a5760405162461bcd60e51b815260040161091890613f4e565b600980547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff848116919091177fffffffff0000000000000000000000000000ffffffffffffffffffffffffffff166e010000000000000000000000000000848316810291909117928390556040517f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad19361324c93818116939091041690613fbc565b60405180910390a15050565b604080516000808252602082019092526001600160a01b0384169083906040516132829190613a5f565b60006040518083038185875af1925050503d80600081146132bf576040519150601f19603f3d011682016040523d82523d6000602084013e6132c4565b606091505b505090508061306d5760405162461bcd60e51b815260040161091890613eba565b6000826132f4575060006108b5565b8282028284828161330157fe5b0414610a805760405162461bcd60e51b815260040161091890613d13565b600082820183811015610a805760405162461bcd60e51b815260040161091890613c6e565b6000610a8083836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506134d1565b600054613393908261331f565b60009081556001600160a01b0383168152600160205260409020546133b8908261331f565b6001600160a01b0383166000818152600160205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612e42908590613b92565b6000818484111561342b5760405162461bcd60e51b81526004016109189190613bed565b505050900390565b6040516370a0823160e01b81526000906001600160a01b038516906370a0823190613462903090600401613ab1565b60206040518083038186803b15801561347a57600080fd5b505afa15801561348e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134b291906138f2565b9050808211156134c0578091505b811561314c5761314c848484612e4e565b600081836134f25760405162461bcd60e51b81526004016109189190613bed565b5060008385816134fe57fe5b0495945050505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061354957805160ff1916838001178555613576565b82800160010185558215613576579182015b8281111561357657825182559160200191906001019061355b565b506135829291506135d3565b5090565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60405180608001604052806004906020820280368337509192915050565b5b8082111561358257600081556001016135d4565b600082601f8301126135f8578081fd5b813567ffffffffffffffff81111561360e578182fd5b6136216020601f19601f84011601614062565b915080825283602082850101111561363857600080fd5b8060208401602084013760009082016020015292915050565b600060a08284031215613662578081fd5b61366c60a0614062565b9050813581526020820135602082015260408201356040820152606082013560608201526080820135608082015292915050565b6000602082840312156136b1578081fd5b8135610a80816140b5565b6000602082840312156136cd578081fd5b8151610a80816140b5565b600080604083850312156136ea578081fd5b82356136f5816140b5565b91506020830135613705816140b5565b809150509250929050565b60008060008060808587031215613725578182fd5b8435613730816140b5565b93506020850135613740816140b5565b9250604085013567ffffffffffffffff8082111561375c578384fd5b613768888389016135e8565b9350606087013591508082111561377d578283fd5b5061378a878288016135e8565b91505092959194509250565b6000806000606084860312156137aa578283fd5b83356137b5816140b5565b925060208401356137c5816140b5565b929592945050506040919091013590565b600080600080600080600060e0888a0312156137f0578283fd5b87356137fb816140b5565b9650602088013561380b816140b5565b95506040880135945060608801359350608088013560ff8116811461382e578384fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561385d578182fd5b8235613868816140b5565b946020939093013593505050565b60008060006060848603121561388a578283fd5b8335613895816140b5565b92506020840135915060408401356138ac816140b5565b809150509250925092565b6000602082840312156138c8578081fd5b81518015158114610a80578182fd5b600060a082840312156138e8578081fd5b610a808383613651565b600060208284031215613903578081fd5b5051919050565b60008060c0838503121561391c578182fd5b823591506111088460208501613651565b6000806040838503121561393f578182fd5b50508035926020909101359150565b600080600060e08486031215613962578081fd5b833592506020840135915061397a8560408601613651565b90509250925092565b6000806000806101008587031215613999578182fd5b8435935060208501359250604085013591506139b88660608701613651565b905092959194509250565b600080600080608085870312156139d8578182fd5b5050823594602084013594506040840135936060013592509050565b600080600080600060a08688031215613a0b578283fd5b5050835160208501516040860151606087015160809097015192989197509594509092509050565b60008151808452613a4b816020860160208601614089565b601f01601f19169290920160200192915050565b60008251613a71818460208701614089565b9190910192915050565b7f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b6001600160a01b03948516815292841660208401526040830191909152909116606082015260800190565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6001600160a01b03929092168252602082015260400190565b60006001600160a01b038516825260ff84166020830152606060408301526123336060830184613a33565b901515815260200190565b90815260200190565b9586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b93845260ff9290921660208401526040830152606082015260800190565b600060208252610a806020830184613a33565b6020808252600d908201527f43506169723a204c4f434b454400000000000000000000000000000000000000604082015260600190565b60208082526019908201527f4345524332303a20494e56414c49445f5349474e415455524500000000000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601c908201527f43506169723a20696e73756666696369656e7420616d6f756e74496e00000000604082015260600190565b60208082526011908201527f43506169723a20494e56414c49445f544f000000000000000000000000000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60408201527f7700000000000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252601c908201527f43506169723a2077726f6e6720616d6f756e74496e206e656564656400000000604082015260600190565b6020808252600f908201527f4345524332303a20455850495245440000000000000000000000000000000000604082015260600190565b60208082526015908201527f43506169723a2077726f6e67206f7574546f6b656e0000000000000000000000604082015260600190565b6020808252601d908201527f43506169723a2053484f52545f4c49515549444954595f4255524e4544000000604082015260600190565b6020808252601d908201527f43506169723a2053484f52545f4c49515549444954595f4d494e544544000000604082015260600190565b60208082526010908201527f43506169723a20464f5242494444454e00000000000000000000000000000000604082015260600190565b60208082526023908201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960408201527f4c45440000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526016908201527f43506169723a205452414e534645525f4641494c454400000000000000000000604082015260600190565b6020808252600f908201527f43506169723a204f564552464c4f570000000000000000000000000000000000604082015260600190565b60208082526015908201527f43506169723a2077726f6e6720616d6f756e74496e0000000000000000000000604082015260600190565b6dffffffffffffffffffffffffffff92831681529116602082015260400190565b918252602082015260400190565b92835260208301919091526001600160a01b0316604082015260600190565b600060e08201905085825260208581840152846040840152606083018460005b60048110156140475781518352918301919083019060010161402a565b5050505095945050505050565b60ff91909116815260200190565b60405181810167ffffffffffffffff8111828210171561408157600080fd5b604052919050565b60005b838110156140a457818101518382015260200161408c565b8381111561314c5750506000910152565b6001600160a01b03811681146140ca57600080fd5b5056fea26469706673582212204d9c04fecc367b0b983af1eb4467f748ca149b973eebf1723301659a88c0b77264736f6c634300060c0033

Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.