ETH Price: $3,255.63 (+4.24%)
Gas: 2 Gwei

Token

ERC20 ***
 

Overview

Max Total Supply

0.000000024987596923 ERC20 ***

Holders

1

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Filtered by Token Holder
nodesale.eth
Balance
0.000000024987595923 ERC20 ***

Value
$0.00
0xd929ff540680f067b6724a9f93ef686cfac5b502
Loading...
Loading
Loading...
Loading
Loading...
Loading

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

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x346E11A4...9D7B2Db3b
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
ImpossiblePair

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license
File 1 of 24 : ImpossibleERC20.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

import './libraries/SafeMath.sol';

import './interfaces/IImpossibleERC20.sol';
import './interfaces/IERC20.sol';

contract ImpossibleERC20 is IImpossibleERC20 {
    using SafeMath for uint256;

    string public override name = 'Impossible Swap LPs';
    string public override symbol = 'IF-LP';
    uint8 public constant override decimals = 18;
    uint256 public override totalSupply;
    mapping(address => uint256) public override balanceOf;
    mapping(address => mapping(address => uint256)) public override allowance;

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

    constructor() {
        // Initializes a placeholder name/domain separator for testing permit typehashs
        _setupDomainSeparator();
    }

    function _initBetterDesc(address _token0, address _token1) internal {
        // This sets name/symbol to include tokens in LP token
        string memory desc = string(abi.encodePacked(IERC20(_token0).symbol(), '/', IERC20(_token1).symbol()));
        name = string(abi.encodePacked('Impossible Swap LPs: ', desc));
        symbol = string(abi.encodePacked('IF-LP: ', desc));
        _setupDomainSeparator();
    }

    function _setupDomainSeparator() internal {
        uint256 chainId;
        assembly {
            chainId := chainid()
        }
        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
                keccak256(bytes(name)),
                keccak256(bytes('1')),
                chainId,
                address(this)
            )
        );
    }

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

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

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

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

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

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

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

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external override {
        require(deadline >= block.timestamp, 'IF: 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, 'IF: INVALID_SIGNATURE');
        _approve(owner, spender, value);
    }
}

File 2 of 24 : SafeMath.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)

library SafeMath {
    function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x + y) >= x, 'ds-math-add-overflow');
    }

    function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x - y) <= x, 'ds-math-sub-underflow');
    }

    function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
    }

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

File 3 of 24 : IImpossibleERC20.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

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

    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function decimals() external view returns (uint8);

    function totalSupply() external view returns (uint256);

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

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);

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

    function transferFrom(
        address from,
        address to,
        uint256 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 (uint256);

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

File 4 of 24 : IERC20.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

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

    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function decimals() external view returns (uint8);

    function totalSupply() external view returns (uint256);

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

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);

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

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool);
}

File 5 of 24 : ERC20.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

import '../ImpossibleERC20.sol';

contract ERC20 is ImpossibleERC20 {
    constructor(uint256 _totalSupply) {
        _mint(msg.sender, _totalSupply);
    }
}

File 6 of 24 : ImpossiblePair.sol
/// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

import './ImpossibleERC20.sol';

import './libraries/Math.sol';
import './libraries/ReentrancyGuard.sol';

import './interfaces/IImpossiblePair.sol';
import './interfaces/IERC20.sol';
import './interfaces/IImpossibleSwapFactory.sol';
import './interfaces/IImpossibleCallee.sol';

/**
    @title  Pair contract for Impossible Swap V3
    @author Impossible Finance
    @notice This factory builds upon basic Uni V2 Pair by adding xybk
            invariant, ability to switch between invariants/boost levels,
            and ability to set asymmetrical tuning.
    @dev    See documentation at: https://docs.impossible.finance/impossible-swap/overview
*/

contract ImpossiblePair is IImpossiblePair, ImpossibleERC20, ReentrancyGuard {
    using SafeMath for uint256;

    uint256 public constant override MINIMUM_LIQUIDITY = 10**3;
    bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));

    /**
     @dev Timestamps, not block numbers
    */
    uint256 private constant THIRTY_MINS = 108000;
    uint32 private constant TWO_WEEKS = 1209600;
    uint32 private constant ONE_DAY = 86400;

    /**
     @dev tradeFee is fee collected per swap in basis points. Init at 30bp.
    */
    uint16 private tradeFee = 30;

    /**
     @dev tradeState Tracks what directional trades are allowed for this pair.
    */
    TradeState private tradeState;

    bool private isXybk;

    address public override factory;
    address public override token0;
    address public override token1;
    address public router;
    address public routerExtension;

    uint128 private reserve0;
    uint128 private reserve1;

    uint256 public kLast;

    /**
     @dev These are the variables for boost.
     @dev Boosts in practice are a function of oldBoost, newBoost, startBlock and endBlock
     @dev We linearly interpolate between oldBoost and newBoost over the blocks
     @dev Note that governance being able to instantly change boosts is dangerous
     @dev Boost0 applies when pool balance0 >= balance1 (when token1 is the more expensive token)
     @dev Boost1 applies when pool balance1 > balance0 (when token0 is the more expensive token)
    */
    uint32 private oldBoost0 = 1;
    uint32 private oldBoost1 = 1;
    uint32 private newBoost0 = 1;
    uint32 private newBoost1 = 1;
    uint32 private currBoost0 = 1;
    uint32 private currBoost1 = 1;

    /**
     @dev BSC mines 10m blocks a year. uint32 will last 400 years before overflowing
    */
    uint256 public startTime;
    uint256 public endTime;

    /**
     @dev withdrawalFeeRatio is the fee collected on burn. Init as 1/201=0.4795% fee (if feeOn)
    */
    uint256 public withdrawalFeeRatio = 201; //

    /**
     @dev Delay sets the duration for boost changes over time. Init as 1 day
     @dev In test environment, set to 50 blocks.
    */
    uint256 public override delay = ONE_DAY;

    modifier onlyIFRouter() {
        require(msg.sender == router || msg.sender == routerExtension, 'IF: FORBIDDEN');
        _;
    }

    modifier onlyGovernance() {
        require(msg.sender == IImpossibleSwapFactory(factory).governance(), 'IF: FORBIDDEN');
        _;
    }

    /**
     @notice Gets the fee per swap in basis points, as well as if this pair is uni or xybk
     @return _tradeFee Fee per swap in basis points
     @return _tradeState What trades are allowed for this pair
     @return _isXybk Boolean if this swap is using uniswap or xybk
    */
    function getPairSettings()
        external
        view
        override
        returns (
            uint16 _tradeFee,
            TradeState _tradeState,
            bool _isXybk
        )
    {
        _tradeFee = tradeFee;
        _tradeState = tradeState;
        _isXybk = isXybk;
    }

    /**
     @notice Gets the reserves in the pair contract
     @return _reserve0 Reserve amount of token0 in the pair
     @return _reserve1 Reserve amount of token1 in the pair
    */
    function getReserves() public view override returns (uint256 _reserve0, uint256 _reserve1) {
        _reserve0 = uint256(reserve0);
        _reserve1 = uint256(reserve1);
    }

    /**
     @notice Getter for the stored boost state
     @dev Helper function for internal use. If uni invariant, all boosts=1
     @return _newBoost0 New boost0 value
     @return _newBoost1 New boost1 value
     @return _oldBoost0 Old boost0 value
     @return _oldBoost1 Old boost1 value
    */
    function getBoost()
        internal
        view
        returns (
            uint32 _newBoost0,
            uint32 _newBoost1,
            uint32 _oldBoost0,
            uint32 _oldBoost1,
            uint32 _currBoost0,
            uint32 _currBoost1
        )
    {
        _newBoost0 = newBoost0;
        _newBoost1 = newBoost1;
        _oldBoost0 = oldBoost0;
        _oldBoost1 = oldBoost1;
        _currBoost0 = currBoost0;
        _currBoost1 = currBoost1;
    }

    /**
     @notice Helper function to calculate a linearly interpolated boost
     @dev Calculations: old + |new - old| * (curr-start)/end-start
     @param oldBst The old boost
     @param newBst The new boost
     @param end The endblock which linear interpolation ends at
     @return uint256 Linearly interpolated boost value
    */
    function linInterpolate(
        uint32 oldBst,
        uint32 newBst,
        uint256 end
    ) internal view returns (uint256) {
        uint256 start = startTime;
        if (newBst > oldBst) {
            /// old + diff * (curr-start) / (end-start)
            return
                uint256(oldBst).add(
                    (uint256(newBst).sub(uint256(oldBst))).mul(block.timestamp.sub(start)).div(end.sub(start))
                );
        } else {
            /// old - diff * (curr-start) / (end-start)
            return
                uint256(oldBst).sub(
                    (uint256(oldBst).sub(uint256(newBst))).mul(block.timestamp.sub(start)).div(end.sub(start))
                );
        }
    }

    /**
     @notice Function to get/calculate actual boosts in the system
     @dev If block.timestamp > endBlock, just return new boosts
     @return _boost0 The actual boost0 value
     @return _boost1 The actual boost1 value
    */
    function calcBoost() public view override returns (uint256 _boost0, uint256 _boost1) {
        uint256 _endTime = endTime;
        if (block.timestamp >= _endTime) {
            (uint32 _newBoost0, uint32 _newBoost1, , , , ) = getBoost();
            _boost0 = uint256(_newBoost0);
            _boost1 = uint256(_newBoost1);
        } else {
            (
                uint32 _newBoost0,
                uint32 _newBoost1,
                uint32 _oldBoost0,
                uint32 _oldBoost1,
                uint32 _currBoost0,
                uint32 _currBoost1
            ) = getBoost();
            _boost0 = linInterpolate(_oldBoost0, _newBoost0, _endTime);
            _boost1 = linInterpolate(_oldBoost1, _newBoost1, _endTime);
            if (xybkComputeK(_boost0, _boost1) < kLast) {
                _boost0 = _currBoost0;
                _boost1 = _currBoost1;
            }
        }
    }

    function calcBoostWithUpdate() internal returns (uint256 _boost0, uint256 _boost1) {
        (_boost0, _boost1) = calcBoost();
        currBoost0 = uint32(_boost0);
        currBoost1 = uint32(_boost1);
    }

    /**
     @notice Safe transfer implementation for tokens
     @dev Requires the transfer to succeed and return either null or True
     @param token The token to transfer
     @param to The address to transfer to
     @param value The amount of tokens to transfer
    */
    function _safeTransfer(
        address token,
        address to,
        uint256 value
    ) private {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'IF: TRANSFER_FAILED');
    }

    /**
     @notice Switches pool from uniswap invariant to xybk invariant
     @dev Can only be called by IF governance
     @dev Requires the pool to be uniswap invariant currently
     @param _newBoost0 The new boost0
     @param _newBoost1 The new boost1
    */
    function makeXybk(uint32 _newBoost0, uint32 _newBoost1) external onlyGovernance nonReentrant {
        require(!isXybk, 'IF: IS_ALREADY_XYBK');
        _updateBoost(_newBoost0, _newBoost1);
        isXybk = true;
        emit ChangeInvariant(isXybk, _newBoost0, _newBoost1);
    }

    /**
     @notice Switches pool from xybk invariant to uniswap invariant
     @dev Can only be called by IF governance
     @dev Requires the pool to be xybk invariant currently
    */
    function makeUni() external onlyGovernance nonReentrant {
        require(isXybk, 'IF: IS_ALREADY_UNI');
        require(block.timestamp >= endTime, 'IF: BOOST_ALREADY_CHANGING');
        require(newBoost0 == 1 && newBoost1 == 1, 'IF: INVALID_BOOST');
        isXybk = false;
        oldBoost0 = 1; // Set boost to 1
        oldBoost1 = 1; // xybk with boost=1 is just xy=k formula
        emit ChangeInvariant(isXybk, newBoost0, newBoost1);
    }

    /**
     @notice Setter function for trade fee per swap
     @dev Can only be called by IF governance
     @dev uint8 fee means 255 basis points max, or max trade fee of 2.56%
     @dev uint8 type means fee cannot be negative
     @param _newFee The new trade fee collected per swap, in basis points
    */
    function updateTradeFees(uint8 _newFee) external onlyGovernance {
        uint16 _oldFee = tradeFee;
        tradeFee = uint16(_newFee);
        emit UpdatedTradeFees(_oldFee, _newFee);
    }

    /**
     @notice Setter function for time delay for boost changes
     @dev Can only be called by IF governance
     @dev Delay must be between 30 minutes and 2 weeks
     @param _newDelay The new time delay in seconds
    */
    function updateDelay(uint256 _newDelay) external onlyGovernance {
        require(_newDelay >= THIRTY_MINS && delay <= TWO_WEEKS, 'IF: INVALID_DELAY');
        uint256 _oldDelay = delay;
        delay = _newDelay;
        emit UpdatedDelay(_oldDelay, _newDelay);
    }

    /**
     @notice Setter function for trade state for this pair
     @dev Can only be called by IF governance
     @param _tradeState See line 45 for TradeState enum settings
    */
    function updateTradeState(TradeState _tradeState) external onlyGovernance nonReentrant {
        require(isXybk, 'IF: IS_CURRENTLY_UNI');
        tradeState = _tradeState;
        emit UpdatedTradeState(_tradeState);
    }

    /**
     @notice Setter function for pool boost state
     @dev Can only be called by IF governance
     @dev Pool has to be using xybk invariant to update boost
     @param _newBoost0 The new boost0
     @param _newBoost1 The new boost1
    */
    function updateBoost(uint32 _newBoost0, uint32 _newBoost1) external onlyGovernance nonReentrant {
        require(isXybk, 'IF: IS_CURRENTLY_UNI');
        _updateBoost(_newBoost0, _newBoost1);
    }

    /**
     @notice Internal helper function to change boosts
     @dev _newBoost0 and _newBoost1 have to be between 1 and 1000000
     @dev Pool cannot already have changing boosts
     @param _newBoost0 The new boost0
     @param _newBoost1 The new boost1
    */
    function _updateBoost(uint32 _newBoost0, uint32 _newBoost1) internal {
        require(
            _newBoost0 >= 1 && _newBoost1 >= 1 && _newBoost0 <= 1000000 && _newBoost1 <= 1000000,
            'IF: INVALID_BOOST'
        );
        uint256 _blockTimestamp = block.timestamp;
        require(_blockTimestamp >= endTime, 'IF: BOOST_ALREADY_CHANGING');
        (uint256 _reserve0, uint256 _reserve1) = getReserves();
        _mintFee(_reserve0, _reserve1);
        oldBoost0 = newBoost0;
        oldBoost1 = newBoost1;
        newBoost0 = _newBoost0;
        newBoost1 = _newBoost1;
        startTime = _blockTimestamp;
        endTime = _blockTimestamp + delay;
        emit UpdatedBoost(oldBoost0, oldBoost1, newBoost0, newBoost1, startTime, endTime);
    }

    /**
     @notice Setter function for the withdrawal fee that goes to Impossible per burn
     @dev Can only be called by IF governance
     @dev Fee is 1/_newFeeRatio. So <1% is 1/(>=100)
     @param _newFeeRatio The new fee ratio
    */
    function updateWithdrawalFeeRatio(uint256 _newFeeRatio) external onlyGovernance {
        require(_newFeeRatio >= 100, 'IF: INVALID_FEE'); // capped at 1%
        uint256 _oldFeeRatio = withdrawalFeeRatio;
        withdrawalFeeRatio = _newFeeRatio;
        emit UpdatedWithdrawalFeeRatio(_oldFeeRatio, _newFeeRatio);
    }

    /**
     @notice Constructor function for pair address
     @dev For pairs associated with IF swap, msg.sender is always the factory
    */
    constructor() {
        factory = msg.sender;
    }

    /**
     @notice Initialization function by factory on deployment
     @dev Can only be called by factory, and will only be called once
     @dev _initBetterDesc adds token0/token1 symbols to ERC20 LP name, symbol
     @param _token0 Address of token0 in pair
     @param _token0 Address of token1 in pair
     @param _router Address of trusted IF router
    */
    function initialize(
        address _token0,
        address _token1,
        address _router,
        address _routerExtension
    ) external override {
        require(msg.sender == factory, 'IF: FORBIDDEN');
        router = _router;
        routerExtension = _routerExtension;
        token0 = _token0;
        token1 = _token1;
        _initBetterDesc(_token0, _token1);
    }

    /**
     @notice Updates reserve state in pair
     @dev No TWAP/oracle functionality
     @param balance0 The new balance for token0
     @param balance1 The new balance for token1
    */
    function _update(uint256 balance0, uint256 balance1) private {
        reserve0 = uint128(balance0);
        reserve1 = uint128(balance1);
        emit Sync(reserve0, reserve1);
    }

    /**
     @notice Mints fee to IF governance multisig treasury
     @dev If feeOn, mint liquidity equal to 4/5th of growth in sqrt(K)
     @param _reserve0 The latest balance for token0 for fee calculations
     @param _reserve1 The latest balance for token1 for fee calculations
     @return feeOn If the mint/burn fee is turned on in this pair
    */
    function _mintFee(uint256 _reserve0, uint256 _reserve1) private returns (bool feeOn) {
        address feeTo = IImpossibleSwapFactory(factory).feeTo();
        feeOn = feeTo != address(0);
        uint256 oldK = kLast; // gas savings
        if (feeOn) {
            if (oldK != 0) {
                (uint256 _boost0, uint256 _boost1) = calcBoostWithUpdate();
                uint256 newRootK = isXybk
                    ? Math.sqrt(xybkComputeK(_boost0, _boost1))
                    : Math.sqrt(_reserve0.mul(_reserve1));
                uint256 oldRootK = Math.sqrt(oldK);
                if (newRootK > oldRootK) {
                    uint256 numerator = totalSupply.mul(newRootK.sub(oldRootK)).mul(4);
                    uint256 denominator = newRootK.add(oldRootK.mul(4));
                    uint256 liquidity = numerator / denominator;
                    if (liquidity > 0) _mint(feeTo, liquidity);
                }
            }
        } else if (oldK != 0) {
            kLast = 0;
        }
    }

    /**
     @notice Mints LP tokens based on sent underlying tokens. Underlying tokens must already be sent to contract
     @dev Function should be called from IF router unless you know what you're doing
     @dev Openzeppelin reentrancy guards are used
     @dev First mint must have both token0 and token1. 
     @param to The address to mint LP tokens to
     @return liquidity The amount of LP tokens minted
    */
    function mint(address to) external override nonReentrant returns (uint256 liquidity) {
        (uint256 _reserve0, uint256 _reserve1) = getReserves(); // gas savings
        uint256 balance0 = IERC20(token0).balanceOf(address(this));
        uint256 balance1 = IERC20(token1).balanceOf(address(this));
        uint256 amount0 = balance0.sub(_reserve0);
        uint256 amount1 = balance1.sub(_reserve1);

        bool feeOn = _mintFee(_reserve0, _reserve1);
        uint256 _totalSupply = totalSupply; // gas savings
        if (_totalSupply == 0) {
            liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
            _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
        } else {
            liquidity = Math.min(
                _reserve0 > 0 ? amount0.mul(_totalSupply) / _reserve0 : uint256(-1),
                _reserve1 > 0 ? amount1.mul(_totalSupply) / _reserve1 : uint256(-1)
            );
        }
        require(liquidity > 0, 'IF: INSUFFICIENT_LIQUIDITY_MINTED');
        _mint(to, liquidity);

        _update(balance0, balance1);
        (uint256 _boost0, uint256 _boost1) = calcBoostWithUpdate();
        if (feeOn) kLast = isXybk ? xybkComputeK(_boost0, _boost1) : balance0.mul(balance1);
        emit Mint(msg.sender, amount0, amount1);
    }

    /**
     @notice Burns LP tokens and returns underlying tokens. LP tokens must already be sent to contract
     @dev Function should be called from IF router unless you know what you're doing
     @dev Openzeppelin reentrancy guards are used
     @param to The address to send underlying tokens to
     @return amount0 The amount of token0's sent
     @return amount1 The amount of token1's sent
    */
    function burn(address to) external override nonReentrant returns (uint256 amount0, uint256 amount1) {
        (uint256 _reserve0, uint256 _reserve1) = getReserves(); // gas savings
        bool feeOn = _mintFee(_reserve0, _reserve1);
        address _token0 = token0; // gas savings
        address _token1 = token1; // gas savings
        uint256 balance0 = IERC20(_token0).balanceOf(address(this));
        uint256 balance1 = IERC20(_token1).balanceOf(address(this));
        uint256 liquidity = balanceOf[address(this)];

        {
            uint256 _totalSupply = totalSupply;
            amount0 = liquidity.mul(balance0) / _totalSupply;
            amount1 = liquidity.mul(balance1) / _totalSupply;
            require(amount0 > 0 || amount1 > 0, 'IF: INSUFFICIENT_LIQUIDITY_BURNED');

            address _feeTo = IImpossibleSwapFactory(factory).feeTo();
            // Burning fees are paid if burn tx doesnt originate from not IF fee collector
            if (feeOn && tx.origin != _feeTo) {
                uint256 _feeRatio = withdrawalFeeRatio; // default is 1/201 ~= 0.4975%
                amount0 -= amount0.div(_feeRatio);
                amount1 -= amount1.div(_feeRatio);
                // Transfers withdrawalFee of LP tokens to IF feeTo
                uint256 transferAmount = liquidity.div(_feeRatio);
                _safeTransfer(address(this), IImpossibleSwapFactory(factory).feeTo(), transferAmount);
                _burn(address(this), liquidity.sub(transferAmount));
            } else {
                _burn(address(this), liquidity);
            }

            _safeTransfer(_token0, to, amount0);
            _safeTransfer(_token1, to, amount1);
        }

        {
            balance0 = IERC20(_token0).balanceOf(address(this));
            balance1 = IERC20(_token1).balanceOf(address(this));
            _update(balance0, balance1);
            if (feeOn) kLast = isXybk ? xybkComputeK(balance0, balance1) : balance0.mul(balance1);
        }
        emit Burn(msg.sender, amount0, amount1, to);
    }

    /**
     @notice Performs a swap operation. Tokens must already be sent to contract
     @dev Input/output amount of tokens must >0 and pool needs to have sufficient liquidity
     @dev Openzeppelin reentrancy guards are used
     @dev Post-swap invariant check is performed (either uni or xybk)
     @param amount0Out The amount of token0's to output
     @param amount1Out The amount of token1's to output
     @param to The address to output tokens to
     @param data Call data allowing for another function call
    */
    function swap(
        uint256 amount0Out,
        uint256 amount1Out,
        address to,
        bytes calldata data
    ) external override onlyIFRouter nonReentrant {
        require(amount0Out > 0 || amount1Out > 0, 'IF: INSUFFICIENT_OUTPUT_AMOUNT');
        (uint256 _reserve0, uint256 _reserve1) = getReserves(); // gas savings
        require(amount0Out <= _reserve0 && amount1Out <= _reserve1, 'IF: INSUFFICIENT_LIQUIDITY');

        uint256 balance0;
        uint256 balance1;
        uint256 amount0In;
        uint256 amount1In;
        {
            require(to != token0 && to != token1, 'IF: INVALID_TO');
            if (amount0Out > 0) _safeTransfer(token0, to, amount0Out); // optimistically transfer tokens
            if (amount1Out > 0) _safeTransfer(token1, to, amount1Out); // optimistically transfer tokens
            if (data.length > 0) IImpossibleCallee(to).ImpossibleCall(msg.sender, amount0Out, amount1Out, data);
            balance0 = IERC20(token0).balanceOf(address(this));
            balance1 = IERC20(token1).balanceOf(address(this));
            // Check bounds
            amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
            amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
        }

        require(amount0In > 0 || amount1In > 0, 'IF: INSUFFICIENT_INPUT_AMOUNT');

        {
            // Avoid stack too deep errors
            bool _isXybk = isXybk;
            uint256 _tradeFee = uint256(tradeFee);
            uint256 balance0Adjusted = balance0.mul(10000).sub(amount0In.mul(_tradeFee)); // tradeFee amt of basis pts
            uint256 balance1Adjusted = balance1.mul(10000).sub(amount1In.mul(_tradeFee)); // tradeFee amt of basis pts
            if (_isXybk) {
                // Check if trade is legal
                TradeState _tradeState = tradeState;
                require(
                    (_tradeState == TradeState.SELL_ALL) ||
                        (_tradeState == TradeState.SELL_TOKEN_0 && amount1Out == 0) ||
                        (_tradeState == TradeState.SELL_TOKEN_1 && amount0Out == 0),
                    'IF: TRADE_NOT_ALLOWED'
                );

                (uint256 boost0, uint256 boost1) = calcBoost(); // dont update boost
                uint256 scaledOldK = xybkComputeK(boost0, boost1).mul(10000**2);
                require(
                    xybkCheckK(boost0, boost1, balance0Adjusted, balance1Adjusted, scaledOldK),
                    'IF: INSUFFICIENT_XYBK_K'
                );
            } else {
                require(
                    balance0Adjusted.mul(balance1Adjusted) >= _reserve0.mul(_reserve1).mul(10000**2),
                    'IF: INSUFFICIENT_UNI_K'
                );
            }
        }

        _update(balance0, balance1);

        emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
    }

    /** 
     @notice Calculates xybk K value
     @dev Uses library function, same as router
     @param _boost0 boost0 to calculate xybk K with
     @param _boost1 boost1 to calculate xybk K with
     @return k The k value given these reserves and boost values
     */
    function xybkComputeK(uint256 _boost0, uint256 _boost1) internal view returns (uint256 k) {
        (uint256 _reserve0, uint256 _reserve1) = getReserves();
        uint256 boost = (_reserve0 > _reserve1) ? _boost0.sub(1) : _boost1.sub(1);
        uint256 denom = boost.mul(2).add(1); // 1+2*boost
        uint256 term = boost.mul(_reserve0.add(_reserve1)).div(denom.mul(2)); // boost*(x+y)/(2+4*boost)
        k = (Math.sqrt(term**2 + _reserve0.mul(_reserve1).div(denom)) + term)**2;
    }

    /**
     @notice Performing K invariant check through an approximation from old K
     @dev More details on math at: https://docs.impossible.finance/impossible-swap/swap-math
     @dev If K_new >= K_old, correctness should still hold
     @param boost0 Current boost0 in pair
     @param boost1 Current boost1 in pair
     @param balance0 Current state of balance0 in pair
     @param balance1 Current state of balance1 in pair
     @param oldK The pre-swap K value
     @return bool Whether the new balances satisfy the K check for xybk
    */
    function xybkCheckK(
        uint256 boost0,
        uint256 boost1,
        uint256 balance0,
        uint256 balance1,
        uint256 oldK
    ) internal pure returns (bool) {
        uint256 oldSqrtK = Math.sqrt(oldK);
        uint256 boost = (balance0 > balance1) ? boost0.sub(1) : boost1.sub(1);
        uint256 innerTerm = boost.mul(oldSqrtK);
        return (balance0.add(innerTerm)).mul(balance1.add(innerTerm)).div((boost.add(1))**2) >= oldK;
    }

    /**
     @notice Forces balances to match reserves
     @dev Requires balance0 >= reserve0 and balance1 >= reserve1
     @param to Address to send excess underlying tokens to
    */
    function skim(address to) external override nonReentrant {
        address _token0 = token0; // gas savings
        address _token1 = token1; // gas savings
        (uint256 _reserve0, uint256 _reserve1) = getReserves();
        _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(_reserve0));
        _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(_reserve1));
    }

    /**
     @notice Forces reserves to match balances
    */
    function sync() external override nonReentrant {
        uint256 _balance0 = IERC20(token0).balanceOf(address(this));
        uint256 _balance1 = IERC20(token1).balanceOf(address(this));
        _update(_balance0, _balance1);
    }
}

File 7 of 24 : Math.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

// a library for performing various math operations

library Math {
    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x < y ? x : y;
    }

    // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
    function sqrt(uint256 y) internal pure returns (uint256 z) {
        if (y > 3) {
            z = y;
            uint256 x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
        } else if (y != 0) {
            z = 1;
        }
    }
}

File 8 of 24 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, 'ReentrancyGuard: reentrant call');

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 9 of 24 : IImpossiblePair.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

import './IImpossibleERC20.sol';

interface IImpossiblePair is IImpossibleERC20 {
    enum TradeState {
        SELL_ALL,
        SELL_TOKEN_0,
        SELL_TOKEN_1,
        SELL_NONE
    }

    event Mint(address indexed sender, uint256 amount0, uint256 amount1);
    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint256 amount0In,
        uint256 amount1In,
        uint256 amount0Out,
        uint256 amount1Out,
        address indexed to
    );
    event Sync(uint256 reserve0, uint256 reserve1);
    event ChangeInvariant(bool _isXybk, uint256 _newBoost0, uint256 _newBoost1);
    event UpdatedTradeFees(uint256 _oldFee, uint256 _newFee);
    event UpdatedDelay(uint256 _oldDelay, uint256 _newDelay);
    event UpdatedTradeState(TradeState _tradeState);
    event UpdatedWithdrawalFeeRatio(uint256 _oldWithdrawalFee, uint256 _newWithdrawalFee);
    event UpdatedBoost(
        uint32 _oldBoost0,
        uint32 _oldBoost1,
        uint32 _newBoost0,
        uint32 _newBoost1,
        uint256 _start,
        uint256 _end
    );

    function MINIMUM_LIQUIDITY() external pure returns (uint256);

    function factory() external view returns (address);

    function token0() external view returns (address); // address of token0

    function token1() external view returns (address); // address of token1

    function getReserves() external view returns (uint256, uint256); // reserves of token0/token1

    function calcBoost() external view returns (uint256, uint256);

    function mint(address) external returns (uint256);

    function burn(address) external returns (uint256, uint256);

    function swap(
        uint256,
        uint256,
        address,
        bytes calldata
    ) external;

    function skim(address to) external;

    function sync() external;

    function getPairSettings()
        external
        view
        returns (
            uint16,
            TradeState,
            bool
        ); // Uses single storage slot, save gas

    function delay() external view returns (uint256); // Amount of time delay required before any change to boost etc, denoted in seconds

    function initialize(
        address,
        address,
        address,
        address
    ) external;
}

File 10 of 24 : IImpossibleSwapFactory.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

interface IImpossibleSwapFactory {
    event PairCreated(address indexed token0, address indexed token1, address pair, uint256);
    event UpdatedGovernance(address governance);

    function feeTo() external view returns (address);

    function governance() external view returns (address);

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

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

    function allPairsLength() external view returns (uint256);

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

    function setFeeTo(address) external;

    function setGovernance(address) external;
}

File 11 of 24 : IImpossibleCallee.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

interface IImpossibleCallee {
    function ImpossibleCall(
        address sender,
        uint256 amount0,
        uint256 amount1,
        bytes calldata data
    ) external;
}

File 12 of 24 : ImpossibleSwapFactory.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

import './ImpossiblePair.sol';
import './ImpossibleWrappedToken.sol';

import './interfaces/IImpossibleSwapFactory.sol';

/**
    @title  Swap Factory for Impossible Swap V3
    @author Impossible Finance
    @notice This factory builds upon basic Uni V2 factory by changing "feeToSetter"
            to "governance" and adding a whitelist
    @dev    See documentation at: https://docs.impossible.finance/impossible-swap/overview
*/

contract ImpossibleSwapFactory is IImpossibleSwapFactory {
    address public override feeTo;
    address public override governance;
    address public router;
    address public routerExtension;
    bool public whitelist;
    mapping(address => bool) public approvedTokens;

    mapping(address => mapping(address => address)) public override getPair;
    address[] public override allPairs;

    /**
     @notice The constructor for the IF swap factory
     @param _governance The address for IF Governance
    */
    constructor(address _governance) {
        governance = _governance;
    }

    modifier onlyGovernance() {
        require(msg.sender == governance, 'IF: FORBIDDEN');
        _;
    }

    /**
     @notice The constructor for the IF swap factory
     @dev _governance The address for IF Governance
     @return uint256 The current number of pairs in the IF swap
    */
    function allPairsLength() external view override returns (uint256) {
        return allPairs.length;
    }

    /**
     @notice Sets router address in factory
     @dev Router is checked in pair contracts to ensure calls are from IF routers only
     @dev Can only be set by IF governance
     @param _router The address of the IF router
     @param _routerExtension The address of the IF router extension
    */
    function setRouterAndExtension(address _router, address _routerExtension) external onlyGovernance {
        router = _router;
        routerExtension = _routerExtension;
    }

    /**
     @notice Either allow or stop a token from being a valid token for new pair contracts
     @dev Changes can only be made by IF governance
     @param token The address of the token
     @param allowed The boolean to include/exclude this token in the whitelist
    */
    function changeTokenAccess(address token, bool allowed) external onlyGovernance {
        approvedTokens[token] = allowed;
    }

    /**
     @notice Turns on or turns off the whitelist feature
     @dev Can only be set by IF governance
     @param b The boolean that whitelist is set to
    */
    function setWhitelist(bool b) external onlyGovernance {
        whitelist = b;
    }

    /**
     @notice Creates a new Impossible Pair contract
     @dev If whitelist is on, can only use approved tokens in whitelist
     @dev tokenA must not be equal to tokenB
     @param tokenA The address of token A. Token A will be in the new Pair contract
     @param tokenB The address of token B. Token B will be in the new Pair contract
     @return pair The address of the created pair containing token A and token B
    */
    function createPair(address tokenA, address tokenB) external override returns (address pair) {
        if (whitelist) {
            require(approvedTokens[tokenA] && approvedTokens[tokenB], 'IF: RESTRICTED_TOKENS');
        }
        require(tokenA != tokenB, 'IF: IDENTICAL_ADDRESSES');
        (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        require(token0 != address(0), 'IF: ZERO_ADDRESS');
        require(getPair[token0][token1] == address(0), 'IF: PAIR_EXISTS');

        bytes memory bytecode = type(ImpossiblePair).creationCode;
        bytes32 salt = keccak256(abi.encodePacked(token0, token1));
        assembly {
            pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
        }

        IImpossiblePair(pair).initialize(token0, token1, router, routerExtension);

        getPair[token0][token1] = pair;
        getPair[token1][token0] = pair;
        allPairs.push(pair);
        emit PairCreated(token0, token1, pair, allPairs.length);
    }

    /**
     @notice Sets the address that fees from the swap are paid to
     @dev Can only be called by IF governance
     @param _feeTo The address that will receive swap fees
    */
    function setFeeTo(address _feeTo) external override onlyGovernance {
        feeTo = _feeTo;
    }

    /**
     @notice Sets the address for IF governance
     @dev Can only be called by IF governance
     @param _governance The address of the new IF governance
    */
    function setGovernance(address _governance) external override onlyGovernance {
        governance = _governance;
    }
}

File 13 of 24 : ImpossibleWrappedToken.sol
// SPDX-License-Identifier: GPL-3

pragma solidity =0.7.6;

import './libraries/TransferHelper.sol';
import './libraries/SafeMath.sol';
import './libraries/ReentrancyGuard.sol';

import './interfaces/IImpossibleWrappedToken.sol';
import './interfaces/IERC20.sol';

contract ImpossibleWrappedToken is IImpossibleWrappedToken, ReentrancyGuard {
    using SafeMath for uint256;

    string public override name;
    string public override symbol;
    uint8 public override decimals = 18;
    uint256 public override totalSupply;

    IERC20 public underlying;
    uint256 public underlyingBalance;
    uint256 public ratioNum;
    uint256 public ratioDenom;

    mapping(address => uint256) public override balanceOf;
    mapping(address => mapping(address => uint256)) public override allowance;

    constructor(
        address _underlying,
        uint256 _ratioNum,
        uint256 _ratioDenom
    ) {
        underlying = IERC20(_underlying);
        ratioNum = _ratioNum;
        ratioDenom = _ratioDenom;
        string memory desc = string(abi.encodePacked(underlying.symbol()));
        name = string(abi.encodePacked('IF-Wrapped ', desc));
        symbol = string(abi.encodePacked('WIF ', desc));
    }

    // amt = amount of wrapped tokens
    function deposit(address dst, uint256 sendAmt) public override nonReentrant returns (uint256 wad) {
        TransferHelper.safeTransferFrom(address(underlying), msg.sender, address(this), sendAmt);
        uint256 receiveAmt = IERC20(underlying).balanceOf(address(this)).sub(underlyingBalance);
        wad = receiveAmt.mul(ratioNum).div(ratioDenom);
        balanceOf[dst] = balanceOf[dst].add(wad);
        totalSupply = totalSupply.add(wad);
        underlyingBalance = underlyingBalance.add(receiveAmt);
        emit Transfer(address(0), dst, wad);
    }

    // wad = amount of wrapped tokens
    function withdraw(address dst, uint256 wad) public override nonReentrant returns (uint256 transferAmt) {
        balanceOf[msg.sender] = balanceOf[msg.sender].sub(wad);
        totalSupply = totalSupply.sub(wad);
        transferAmt = wad.mul(ratioDenom).div(ratioNum);
        TransferHelper.safeTransfer(address(underlying), dst, transferAmt);
        underlyingBalance = underlyingBalance.sub(transferAmt);
        emit Transfer(msg.sender, address(0), wad);
    }

    function amtToUnderlyingAmt(uint256 amt) public view override returns (uint256) {
        return amt.mul(ratioDenom).div(ratioNum);
    }

    function approve(address guy, uint256 wad) public override returns (bool) {
        allowance[msg.sender][guy] = wad;
        emit Approval(msg.sender, guy, wad);
        return true;
    }

    function transfer(address dst, uint256 wad) public override returns (bool) {
        require(dst != address(0x0), 'IF Wrapper: INVALID_DST');
        return transferFrom(msg.sender, dst, wad);
    }

    function transferFrom(
        address src,
        address dst,
        uint256 wad
    ) public override returns (bool) {
        require(balanceOf[src] >= wad, '');
        require(dst != address(0x0), 'IF Wrapper: INVALID_DST');

        if (src != msg.sender && allowance[src][msg.sender] != uint256(-1)) {
            require(allowance[src][msg.sender] >= wad, 'ImpossibleWrapper: INSUFF_ALLOWANCE');
            allowance[src][msg.sender] -= wad;
        }

        balanceOf[src] -= wad;
        balanceOf[dst] += wad;

        emit Transfer(src, dst, wad);

        return true;
    }
}

File 14 of 24 : TransferHelper.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity >=0.6.0;

// 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,
        uint256 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::safeApprove: approve failed'
        );
    }

    function safeTransfer(
        address token,
        address to,
        uint256 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::safeTransfer: transfer failed'
        );
    }

    function safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 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::transferFrom: transferFrom failed'
        );
    }

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

File 15 of 24 : IImpossibleWrappedToken.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

import './IERC20.sol';

interface IImpossibleWrappedToken is IERC20 {
    function deposit(address, uint256) external returns (uint256);

    function withdraw(address, uint256) external returns (uint256);

    function amtToUnderlyingAmt(uint256) external returns (uint256);
}

File 16 of 24 : ImpossibleRouterExtension.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

import './interfaces/IImpossiblePair.sol';
import './interfaces/IImpossibleSwapFactory.sol';
import './interfaces/IImpossibleRouterExtension.sol';

import './libraries/ImpossibleLibrary.sol';

contract ImpossibleRouterExtension is IImpossibleRouterExtension {
    address public immutable override factory;

    constructor(address _factory) {
        factory = _factory;
    }

    /**
     @notice Helper function for basic swap
     @dev Requires the initial amount to have been sent to the first pair contract
     @param amounts[] An array of trade amounts. Trades are made from arr idx 0 to arr end idx sequentially
     @param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
    */
    function swap(uint256[] memory amounts, address[] memory path) public override {
        for (uint256 i; i < path.length - 1; i++) {
            (address input, address output) = (path[i], path[i + 1]);
            (address token0, ) = ImpossibleLibrary.sortTokens(input, output);
            uint256 amountOut = amounts[i + 1];
            (uint256 amount0Out, uint256 amount1Out) = input == token0
                ? (uint256(0), amountOut)
                : (amountOut, uint256(0));
            address to = i < path.length - 2 ? ImpossibleLibrary.pairFor(factory, output, path[i + 2]) : msg.sender;
            IImpossiblePair(ImpossibleLibrary.pairFor(factory, input, output)).swap(
                amount0Out,
                amount1Out,
                to,
                new bytes(0)
            );
        }
    }

    /**
     @notice Helper function for swap supporting fee on transfer tokens
     @dev Requires the initial amount to have been sent to the first pair contract
     @param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
    */
    function swapSupportingFeeOnTransferTokens(address[] memory path) public override {
        for (uint256 i; i < path.length - 1; i++) {
            (address input, address output) = (path[i], path[i + 1]);
            (uint256 amount0Out, uint256 amount1Out) = ImpossibleLibrary.getAmountOutFeeOnTransfer(
                input,
                output,
                factory
            );
            address to = i < path.length - 2 ? ImpossibleLibrary.pairFor(factory, output, path[i + 2]) : msg.sender;
            IImpossiblePair(ImpossibleLibrary.pairFor(factory, input, output)).swap(
                amount0Out,
                amount1Out,
                to,
                new bytes(0)
            );
        }
    }

    /**
     @notice Helper function for adding liquidity
     @dev Logic is unchanged from uniswap-V2-Router02
     @param tokenA The address of underlying tokenA to add
     @param tokenB The address of underlying tokenB to add
     @param amountADesired The desired amount of tokenA to add
     @param amountBDesired The desired amount of tokenB to add
     @param amountAMin The min amount of tokenA to add (amountAMin:amountBDesired sets bounds on ratio)
     @param amountBMin The min amount of tokenB to add (amountADesired:amountBMin sets bounds on ratio)
     @return amountA Actual amount of tokenA added as liquidity to pair
     @return amountB Actual amount of tokenB added as liquidity to pair
    */
    function addLiquidity(
        address tokenA,
        address tokenB,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin
    ) public override returns (uint256 amountA, uint256 amountB) {
        // create the pair if it doesn't exist yet
        if (IImpossibleSwapFactory(factory).getPair(tokenA, tokenB) == address(0)) {
            IImpossibleSwapFactory(factory).createPair(tokenA, tokenB);
        }
        (uint256 reserveA, uint256 reserveB, ) = ImpossibleLibrary.getReserves(factory, tokenA, tokenB);
        if (reserveA == 0 && reserveB == 0) {
            (amountA, amountB) = (amountADesired, amountBDesired);
        } else if (reserveA == 0) {
            amountB = amountBDesired;
        } else if (reserveB == 0) {
            amountA = amountADesired;
        } else {
            uint256 amountBOptimal = ImpossibleLibrary.quote(amountADesired, reserveA, reserveB);
            if (amountBOptimal <= amountBDesired) {
                require(amountBOptimal >= amountBMin, 'ImpossibleRouter: INSUFFICIENT_B_AMOUNT');
                (amountA, amountB) = (amountADesired, amountBOptimal);
            } else {
                uint256 amountAOptimal = ImpossibleLibrary.quote(amountBDesired, reserveB, reserveA);
                assert(amountAOptimal <= amountADesired);
                require(amountAOptimal >= amountAMin, 'ImpossibleRouter: INSUFFICIENT_A_AMOUNT');
                (amountA, amountB) = (amountAOptimal, amountBDesired);
            }
        }
    }

    /**
     @notice Helper function for removing liquidity
     @dev Logic is unchanged from uniswap-V2-Router02
     @param tokenA The address of underlying tokenA in LP token
     @param tokenB The address of underlying tokenB in LP token
     @param pair The address of the pair corresponding to tokenA and tokenB
     @param amountAMin The min amount of underlying tokenA that has to be received
     @param amountBMin The min amount of underlying tokenB that has to be received
     @return amountA Actual amount of underlying tokenA received
     @return amountB Actual amount of underlying tokenB received
    */
    function removeLiquidity(
        address tokenA,
        address tokenB,
        address pair,
        uint256 amountAMin,
        uint256 amountBMin
    ) public override returns (uint256 amountA, uint256 amountB) {
        (uint256 amount0, uint256 amount1) = IImpossiblePair(pair).burn(msg.sender);
        (address token0, ) = ImpossibleLibrary.sortTokens(tokenA, tokenB);
        (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
        require(amountA >= amountAMin, 'ImpossibleRouter: INSUFFICIENT_A_AMOUNT');
        require(amountB >= amountBMin, 'ImpossibleRouter: INSUFFICIENT_B_AMOUNT');
    }

    function quote(
        uint256 amountA,
        uint256 reserveA,
        uint256 reserveB
    ) public pure virtual override returns (uint256 amountB) {
        return ImpossibleLibrary.quote(amountA, reserveA, reserveB);
    }

    function getAmountOut(
        uint256 amountIn,
        address tokenIn,
        address tokenOut
    ) public view virtual override returns (uint256 amountOut) {
        return ImpossibleLibrary.getAmountOut(amountIn, tokenIn, tokenOut, factory);
    }

    function getAmountIn(
        uint256 amountOut,
        address tokenIn,
        address tokenOut
    ) public view virtual override returns (uint256 amountIn) {
        return ImpossibleLibrary.getAmountIn(amountOut, tokenIn, tokenOut, factory);
    }

    function getAmountsOut(uint256 amountIn, address[] memory path)
        public
        view
        virtual
        override
        returns (uint256[] memory amounts)
    {
        return ImpossibleLibrary.getAmountsOut(factory, amountIn, path);
    }

    function getAmountsIn(uint256 amountOut, address[] memory path)
        public
        view
        virtual
        override
        returns (uint256[] memory amounts)
    {
        return ImpossibleLibrary.getAmountsIn(factory, amountOut, path);
    }
}

File 17 of 24 : IImpossibleRouterExtension.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

import './IImpossiblePair.sol';

interface IImpossibleRouterExtension {
    function factory() external returns (address factoryAddr);

    function swap(uint256[] memory amounts, address[] memory path) external;

    function swapSupportingFeeOnTransferTokens(address[] memory path) external;

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin
    ) external returns (uint256 amountA, uint256 amountB);

    function removeLiquidity(
        address tokenA,
        address tokenB,
        address pair,
        uint256 amountAMin,
        uint256 amountBMin
    ) external returns (uint256 amountA, uint256 amountB);

    function quote(
        uint256 amountA,
        uint256 reserveA,
        uint256 reserveB
    ) external returns (uint256 amountB);

    function getAmountOut(
        uint256 amountIn,
        address tokenIn,
        address tokenOut
    ) external view returns (uint256 amountOut);

    function getAmountIn(
        uint256 amountOut,
        address tokenIn,
        address tokenOut
    ) external view returns (uint256 amountIn);

    function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts);

    function getAmountsIn(uint256 amountOut, address[] calldata path) external view returns (uint256[] memory amounts);
}

File 18 of 24 : ImpossibleLibrary.sol
/// SPDX-License-Identifier: GPL-3
pragma solidity >=0.5.0;

import '../interfaces/IImpossiblePair.sol';
import '../interfaces/IERC20.sol';

import './SafeMath.sol';
import './Math.sol';

library ImpossibleLibrary {
    using SafeMath for uint256;

    /**
     @notice Sorts tokens in ascending order
     @param tokenA The address of token A
     @param tokenB The address of token B
     @return token0 The address of token 0 (lexicographically smaller than addr of token 1)
     @return token1 The address of token 1 (lexicographically larger than addr of token 0)
    */
    function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
        require(tokenA != tokenB, 'ImpossibleLibrary: IDENTICAL_ADDRESSES');
        (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        require(token0 != address(0), 'ImpossibleLibrary: ZERO_ADDRESS');
    }

    /**
     @notice Computes the pair contract create2 address deterministically
     @param factory The address of the token factory (pair contract deployer)
     @param tokenA The address of token A
     @param tokenB The address of token B
     @return pair The address of the pair containing token A and B
    */
    function pairFor(
        address factory,
        address tokenA,
        address tokenB
    ) internal pure returns (address pair) {
        (address token0, address token1) = sortTokens(tokenA, tokenB);
        pair = address(
            uint256(
                keccak256(
                    abi.encodePacked(
                        hex'ff',
                        factory,
                        keccak256(abi.encodePacked(token0, token1)),
                        hex'fc84b622ba228c468b74c2d99bfe9454ffac280ac017f05a02feb9f739aeb1e4' // init code hash                    
                    )
                )
            )
        );
    }

    /**
     @notice Obtains the token reserves in the pair contract
     @param factory The address of the token factory (pair contract deployer)
     @param tokenA The address of token A
     @param tokenB The address of token B
     @return reserveA The amount of token A in reserves
     @return reserveB The amount of token B in reserves
     @return pair The address of the pair containing token A and B
    */
    function getReserves(
        address factory,
        address tokenA,
        address tokenB
    )
        internal
        view
        returns (
            uint256 reserveA,
            uint256 reserveB,
            address pair
        )
    {
        (address token0, ) = sortTokens(tokenA, tokenB);
        pair = pairFor(factory, tokenA, tokenB);
        (uint256 reserve0, uint256 reserve1) = IImpossiblePair(pair).getReserves();
        (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
    }

    /**
     @notice Quote returns amountB based on some amountA, in the ratio of reserveA:reserveB
     @param amountA The amount of token A
     @param reserveA The amount of reserveA
     @param reserveB The amount of reserveB
     @return amountB The amount of token B that matches amount A in the ratio of reserves
    */
    function quote(
        uint256 amountA,
        uint256 reserveA,
        uint256 reserveB
    ) internal pure returns (uint256 amountB) {
        require(amountA > 0, 'ImpossibleLibrary: INSUFFICIENT_AMOUNT');
        require(reserveA > 0 && reserveB > 0, 'ImpossibleLibrary: INSUFFICIENT_LIQUIDITY');
        amountB = amountA.mul(reserveB) / reserveA;
    }

    /**
     @notice Internal function to compute the K value for an xybk pair based on token balances and boost
     @dev More details on math at: https://docs.impossible.finance/impossible-swap/swap-math
     @dev Implementation is the same as in pair
     @param boost0 Current boost0 in pair
     @param boost1 Current boost1 in pair
     @param balance0 Current state of balance0 in pair
     @param balance1 Current state of balance1 in pair
     @return k Value of K invariant
    */
    function xybkComputeK(
        uint256 boost0,
        uint256 boost1,
        uint256 balance0,
        uint256 balance1
    ) internal pure returns (uint256 k) {
        uint256 boost = (balance0 > balance1) ? boost0.sub(1) : boost1.sub(1);
        uint256 denom = boost.mul(2).add(1); // 1+2*boost
        uint256 term = boost.mul(balance0.add(balance1)).div(denom.mul(2)); // boost*(x+y)/(2+4*boost)
        k = (Math.sqrt(term**2 + balance0.mul(balance1).div(denom)) + term)**2;
    }

    /**
     @notice Internal helper function for calculating artificial liquidity
     @dev More details on math at: https://docs.impossible.finance/impossible-swap/swap-math
     @param _boost The boost variable on the correct side for the pair contract
     @param _sqrtK The sqrt of the invariant variable K in xybk formula
     @return uint256 The artificial liquidity term
    */
    function calcArtiLiquidityTerm(uint256 _boost, uint256 _sqrtK) internal pure returns (uint256) {
        return (_boost - 1).mul(_sqrtK);
    }

    /**
     @notice Quotes maximum output given exact input amount of tokens and addresses of tokens in pair
     @dev The library function considers custom swap fees/invariants/asymmetric tuning of pairs
     @dev However, library function doesn't consider limits created by hardstops
     @param amountIn The input amount of token A
     @param tokenIn The address of input token
     @param tokenOut The address of output token
     @param factory The address of the factory contract
     @return amountOut The maximum output amount of token B for a valid swap
    */
    function getAmountOut(
        uint256 amountIn,
        address tokenIn,
        address tokenOut,
        address factory
    ) internal view returns (uint256 amountOut) {
        require(amountIn > 0, 'ImpossibleLibrary: INSUFFICIENT_INPUT_AMOUNT');
        uint256 reserveIn;
        uint256 reserveOut;
        uint256 amountInPostFee;
        address pair;
        bool isMatch;
        {
            // Avoid stack too deep
            (address token0, ) = sortTokens(tokenIn, tokenOut);
            isMatch = tokenIn == token0;
            (reserveIn, reserveOut, pair) = getReserves(factory, tokenIn, tokenOut);
        }
        uint256 artiLiqTerm;
        bool isXybk;
        {
            // Avoid stack too deep
            uint256 fee;
            IImpossiblePair.TradeState tradeState;
            (fee, tradeState, isXybk) = IImpossiblePair(pair).getPairSettings();
            amountInPostFee = amountIn.mul(10000 - fee);
            require(
                (tradeState == IImpossiblePair.TradeState.SELL_ALL) ||
                    (tradeState == IImpossiblePair.TradeState.SELL_TOKEN_0 && !isMatch) ||
                    (tradeState == IImpossiblePair.TradeState.SELL_TOKEN_1 && isMatch),
                'ImpossibleLibrary: TRADE_NOT_ALLOWED'
            );
        }

        /// If xybk invariant, set reserveIn/reserveOut to artificial liquidity instead of actual liquidity
        if (isXybk) {
            (uint256 boost0, uint256 boost1) = IImpossiblePair(pair).calcBoost();
            uint256 sqrtK = Math.sqrt(
                xybkComputeK(boost0, boost1, isMatch ? reserveIn : reserveOut, isMatch ? reserveOut : reserveIn)
            );
            /// since balance0=balance1 only at sqrtK, if final balanceIn >= sqrtK means balanceIn >= balanceOut
            /// Use post-fee balances to maintain consistency with pair contract K invariant check
            if (amountInPostFee.add(reserveIn.mul(10000)) >= sqrtK.mul(10000)) {
                /// If tokenIn = token0, balanceIn > sqrtK => balance0>sqrtK, use boost0
                artiLiqTerm = calcArtiLiquidityTerm(isMatch ? boost0 : boost1, sqrtK);
                /// If balance started from <sqrtK and ended at >sqrtK and boosts are different, there'll be different amountIn/Out
                /// Don't need to check in other case for reserveIn < reserveIn.add(x) <= sqrtK since that case doesnt cross midpt
                if (reserveIn < sqrtK && boost0 != boost1) {
                    /// Break into 2 trades => start point -> midpoint (sqrtK, sqrtK), then midpoint -> final point
                    amountOut = reserveOut.sub(sqrtK);
                    amountInPostFee = amountInPostFee.sub((sqrtK.sub(reserveIn)).mul(10000));
                    reserveIn = sqrtK;
                    reserveOut = sqrtK;
                }
            } else {
                /// If tokenIn = token0, balanceIn < sqrtK => balance0<sqrtK, use boost1
                artiLiqTerm = calcArtiLiquidityTerm(isMatch ? boost1 : boost0, sqrtK);
            }
        }
        uint256 numerator = amountInPostFee.mul(reserveOut.add(artiLiqTerm));
        uint256 denominator = (reserveIn.add(artiLiqTerm)).mul(10000).add(amountInPostFee);
        uint256 lastSwapAmountOut = numerator / denominator;
        amountOut = (lastSwapAmountOut > reserveOut) ? reserveOut.add(amountOut) : lastSwapAmountOut.add(amountOut);
    }

    /**
     @notice Quotes minimum input given exact output amount of tokens and addresses of tokens in pair
     @dev The library function considers custom swap fees/invariants/asymmetric tuning of pairs
     @dev However, library function doesn't consider limits created by hardstops
     @param amountOut The desired output amount of token A
     @param tokenIn The address of input token
     @param tokenOut The address of output token
     @param factory The address of the factory contract
     @return amountIn The minimum input amount of token A for a valid swap
    */
    function getAmountIn(
        uint256 amountOut,
        address tokenIn,
        address tokenOut,
        address factory
    ) internal view returns (uint256 amountIn) {
        require(amountOut > 0, 'ImpossibleLibrary: INSUFFICIENT_INPUT_AMOUNT');

        uint256 reserveIn;
        uint256 reserveOut;
        uint256 artiLiqTerm;
        uint256 fee;
        bool isMatch;
        {
            // Avoid stack too deep
            bool isXybk;
            uint256 boost0;
            uint256 boost1;
            {
                // Avoid stack too deep
                (address token0, ) = sortTokens(tokenIn, tokenOut);
                isMatch = tokenIn == token0;
            }
            {
                // Avoid stack too deep
                address pair;
                (reserveIn, reserveOut, pair) = getReserves(factory, tokenIn, tokenOut);
                IImpossiblePair.TradeState tradeState;
                (fee, tradeState, isXybk) = IImpossiblePair(pair).getPairSettings();
                require(
                    (tradeState == IImpossiblePair.TradeState.SELL_ALL) ||
                        (tradeState == IImpossiblePair.TradeState.SELL_TOKEN_0 && !isMatch) ||
                        (tradeState == IImpossiblePair.TradeState.SELL_TOKEN_1 && isMatch),
                    'ImpossibleLibrary: TRADE_NOT_ALLOWED'
                );
                (boost0, boost1) = IImpossiblePair(pair).calcBoost();
            }
            if (isXybk) {
                uint256 sqrtK = Math.sqrt(
                    xybkComputeK(boost0, boost1, isMatch ? reserveIn : reserveOut, isMatch ? reserveOut : reserveIn)
                );
                /// since balance0=balance1 only at sqrtK, if final balanceOut >= sqrtK means balanceOut >= balanceIn
                if (reserveOut.sub(amountOut) >= sqrtK) {
                    /// If tokenIn = token0, balanceOut > sqrtK => balance1>sqrtK, use boost1
                    artiLiqTerm = calcArtiLiquidityTerm(isMatch ? boost1 : boost0, sqrtK);
                } else {
                    /// If tokenIn = token0, balanceOut < sqrtK => balance0>sqrtK, use boost0
                    artiLiqTerm = calcArtiLiquidityTerm(isMatch ? boost0 : boost1, sqrtK);
                    /// If balance started from <sqrtK and ended at >sqrtK and boosts are different, there'll be different amountIn/Out
                    /// Don't need to check in other case for reserveOut > reserveOut.sub(x) >= sqrtK since that case doesnt cross midpt
                    if (reserveOut > sqrtK && boost0 != boost1) {
                        /// Break into 2 trades => start point -> midpoint (sqrtK, sqrtK), then midpoint -> final point
                        amountIn = sqrtK.sub(reserveIn).mul(10000); /// Still need to divide by (10000 - fee). Do with below calculation to prevent early truncation
                        amountOut = amountOut.sub(reserveOut.sub(sqrtK));
                        reserveOut = sqrtK;
                        reserveIn = sqrtK;
                    }
                }
            }
        }
        uint256 numerator = (reserveIn.add(artiLiqTerm)).mul(amountOut).mul(10000);
        uint256 denominator = (reserveOut.add(artiLiqTerm)).sub(amountOut);
        amountIn = (amountIn.add((numerator / denominator)).div(10000 - fee)).add(1);
    }

    /**
     @notice Quotes maximum output given some uncertain input amount of tokens and addresses of tokens in pair
     @dev The library function considers custom swap fees/invariants/asymmetric tuning of pairs
     @dev However, library function doesn't consider limits created by hardstops
     @param tokenIn The address of input token
     @param tokenOut The address of output token
     @param factory The address of the factory contract
     @return uint256 The maximum possible output amount of token A
     @return uint256 The maximum possible output amount of token B
    */
    function getAmountOutFeeOnTransfer(
        address tokenIn,
        address tokenOut,
        address factory
    ) internal view returns (uint256, uint256) {
        uint256 reserveIn;
        uint256 reserveOut;
        address pair;
        bool isMatch;
        {
            // Avoid stack too deep
            (address token0, ) = sortTokens(tokenIn, tokenOut);
            isMatch = tokenIn == token0;
            (reserveIn, reserveOut, pair) = getReserves(factory, tokenIn, tokenOut); /// Should be reserve0/1 but reuse variables to save stack
        }
        uint256 amountOut;
        uint256 artiLiqTerm;
        uint256 amountInPostFee;
        bool isXybk;
        {
            // Avoid stack too deep
            uint256 fee;
            uint256 balanceIn = IERC20(tokenIn).balanceOf(address(pair));
            require(balanceIn > reserveIn, 'ImpossibleLibrary: INSUFFICIENT_INPUT_AMOUNT');
            IImpossiblePair.TradeState tradeState;
            (fee, tradeState, isXybk) = IImpossiblePair(pair).getPairSettings();
            require(
                (tradeState == IImpossiblePair.TradeState.SELL_ALL) ||
                    (tradeState == IImpossiblePair.TradeState.SELL_TOKEN_0 && !isMatch) ||
                    (tradeState == IImpossiblePair.TradeState.SELL_TOKEN_1 && isMatch),
                'ImpossibleLibrary: TRADE_NOT_ALLOWED'
            );
            amountInPostFee = (balanceIn.sub(reserveIn)).mul(10000 - fee);
        }
        /// If xybk invariant, set reserveIn/reserveOut to artificial liquidity instead of actual liquidity
        if (isXybk) {
            (uint256 boost0, uint256 boost1) = IImpossiblePair(pair).calcBoost();
            uint256 sqrtK = Math.sqrt(
                xybkComputeK(boost0, boost1, isMatch ? reserveIn : reserveOut, isMatch ? reserveOut : reserveIn)
            );
            /// since balance0=balance1 only at sqrtK, if final balanceIn >= sqrtK means balanceIn >= balanceOut
            /// Use post-fee balances to maintain consistency with pair contract K invariant check
            if (amountInPostFee.add(reserveIn.mul(10000)) >= sqrtK.mul(10000)) {
                /// If tokenIn = token0, balanceIn > sqrtK => balance0>sqrtK, use boost0
                artiLiqTerm = calcArtiLiquidityTerm(isMatch ? boost0 : boost1, sqrtK);
                /// If balance started from <sqrtK and ended at >sqrtK and boosts are different, there'll be different amountIn/Out
                /// Don't need to check in other case for reserveIn < reserveIn.add(x) <= sqrtK since that case doesnt cross midpt
                if (reserveIn < sqrtK && boost0 != boost1) {
                    /// Break into 2 trades => start point -> midpoint (sqrtK, sqrtK), then midpoint -> final point
                    amountOut = reserveOut.sub(sqrtK);
                    amountInPostFee = amountInPostFee.sub(sqrtK.sub(reserveIn));
                    reserveOut = sqrtK;
                    reserveIn = sqrtK;
                }
            } else {
                /// If tokenIn = token0, balanceIn < sqrtK => balance0<sqrtK, use boost0
                artiLiqTerm = calcArtiLiquidityTerm(isMatch ? boost1 : boost0, sqrtK);
            }
        }
        uint256 numerator = amountInPostFee.mul(reserveOut.add(artiLiqTerm));
        uint256 denominator = (reserveIn.add(artiLiqTerm)).mul(10000).add(amountInPostFee);
        uint256 lastSwapAmountOut = numerator / denominator;
        amountOut = (lastSwapAmountOut > reserveOut) ? reserveOut.add(amountOut) : lastSwapAmountOut.add(amountOut);
        return isMatch ? (uint256(0), amountOut) : (amountOut, uint256(0));
    }

    /**
     @notice Quotes maximum output given exact input amount of tokens and addresses of tokens in trade sequence
     @dev The library function considers custom swap fees/invariants/asymmetric tuning of pairs
     @dev However, library function doesn't consider limits created by hardstops
     @param factory The address of the IF factory
     @param amountIn The input amount of token A
     @param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
     @return amounts The maximum possible output amount of all tokens through sequential swaps
    */
    function getAmountsOut(
        address factory,
        uint256 amountIn,
        address[] memory path
    ) internal view returns (uint256[] memory amounts) {
        require(path.length >= 2, 'ImpossibleLibrary: INVALID_PATH');
        amounts = new uint256[](path.length);
        amounts[0] = amountIn;
        for (uint256 i; i < path.length - 1; i++) {
            amounts[i + 1] = getAmountOut(amounts[i], path[i], path[i + 1], factory);
        }
    }

    /**
     @notice Quotes minimum input given exact output amount of tokens and addresses of tokens in trade sequence
     @dev The library function considers custom swap fees/invariants/asymmetric tuning of pairs
     @dev However, library function doesn't consider limits created by hardstops
     @param factory The address of the IF factory
     @param amountOut The output amount of token A
     @param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
     @return amounts The minimum output amount required of all tokens through sequential swaps
    */
    function getAmountsIn(
        address factory,
        uint256 amountOut,
        address[] memory path
    ) internal view returns (uint256[] memory amounts) {
        require(path.length >= 2, 'ImpossibleLibrary: INVALID_PATH');
        amounts = new uint256[](path.length);
        amounts[amounts.length - 1] = amountOut;
        for (uint256 i = path.length - 1; i > 0; i--) {
            amounts[i - 1] = getAmountIn(amounts[i], path[i - 1], path[i], factory);
        }
    }
}

File 19 of 24 : DeflatingERC20.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

import '../libraries/SafeMath.sol';

contract DeflatingERC20 {
    using SafeMath for uint256;

    string public constant name = 'Deflating Test Token';
    string public constant symbol = 'DTT';
    uint8 public constant decimals = 18;
    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

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

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

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

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

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

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

    function _transfer(
        address from,
        address to,
        uint256 value
    ) private {
        uint256 burnAmount = value / 100;
        _burn(from, burnAmount);
        uint256 transferAmount = value.sub(burnAmount);
        balanceOf[from] = balanceOf[from].sub(transferAmount);
        balanceOf[to] = balanceOf[to].add(transferAmount);
        emit Transfer(from, to, transferAmount);
    }

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

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

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

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external {
        require(deadline >= block.timestamp, '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, 'INVALID_SIGNATURE');
        _approve(owner, spender, value);
    }
}

File 20 of 24 : ImpossibleWrapperFactory.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

import './ImpossibleWrappedToken.sol';

import './interfaces/IImpossibleWrapperFactory.sol';
import './interfaces/IERC20.sol';

/**
    @title  Wrapper Factory for Impossible Swap V3
    @author Impossible Finance
    @notice This factory builds upon basic Uni V2 factory by changing "feeToSetter"
            to "governance" and adding a whitelist
    @dev    See documentation at: https://docs.impossible.finance/impossible-swap/overview
*/

contract ImpossibleWrapperFactory is IImpossibleWrapperFactory {
    address public governance;
    mapping(address => address) public override tokensToWrappedTokens;
    mapping(address => address) public override wrappedTokensToTokens;

    /**
     @notice The constructor for the IF swap factory
     @param _governance The address for IF Governance
    */
    constructor(address _governance) {
        governance = _governance;
    }

    modifier onlyGovernance() {
        require(msg.sender == governance, 'IF: FORBIDDEN');
        _;
    }

    /**
     @notice Sets the address for IF governance
     @dev Can only be called by IF governance
     @param _governance The address of the new IF governance
    */
    function setGovernance(address _governance) external onlyGovernance {
        governance = _governance;
    }

    /**
     @notice Creates a pair with some ratio
     @dev underlying The address of token to wrap
     @dev ratioNumerator The numerator value of the ratio to apply for ratio * underlying = wrapped underlying
     @dev ratioDenominator The denominator value of the ratio to apply for ratio * underlying = wrapped underlying
    */
    function createPairing(
        address underlying,
        uint256 ratioNumerator,
        uint256 ratioDenominator
    ) external onlyGovernance returns (address) {
        require(
            tokensToWrappedTokens[underlying] == address(0x0) && wrappedTokensToTokens[underlying] == address(0x0),
            'IF: PAIR_EXISTS'
        );
        require(ratioNumerator != 0 && ratioDenominator != 0, 'IF: INVALID_RATIO');
        ImpossibleWrappedToken wrapper = new ImpossibleWrappedToken(underlying, ratioNumerator, ratioDenominator);
        tokensToWrappedTokens[underlying] = address(wrapper);
        wrappedTokensToTokens[address(wrapper)] = underlying;
        emit WrapCreated(underlying, address(wrapper), ratioNumerator, ratioDenominator);
        return address(wrapper);
    }

    /**
     @notice Deletes a pairing
     @notice requires supply of wrapped token to be 0
     @dev wrapper The address of the wrapper
    */
    function deletePairing(address wrapper) external onlyGovernance {
        require(ImpossibleWrappedToken(wrapper).totalSupply() == 0, 'IF: NONZERO_SUPPLY');
        address _underlying = wrappedTokensToTokens[wrapper];
        require(ImpossibleWrappedToken(wrapper).underlying() == IERC20(_underlying), 'IF: INVALID_TOKEN');
        require(_underlying != address(0x0), 'IF: Address must have pair');
        delete tokensToWrappedTokens[_underlying];
        delete wrappedTokensToTokens[wrapper];
        emit WrapDeleted(_underlying, address(wrapper));
    }
}

File 21 of 24 : IImpossibleWrapperFactory.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;

interface IImpossibleWrapperFactory {
    event WrapCreated(address, address, uint256, uint256);
    event WrapDeleted(address, address);

    function tokensToWrappedTokens(address) external view returns (address);

    function wrappedTokensToTokens(address) external view returns (address);
}

File 22 of 24 : ImpossibleRouter.sol
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import './libraries/TransferHelper.sol';
import './libraries/ReentrancyGuard.sol';
import './libraries/ImpossibleLibrary.sol';
import './libraries/SafeMath.sol';

import './interfaces/IImpossibleSwapFactory.sol';
import './interfaces/IImpossibleRouterExtension.sol';
import './interfaces/IImpossibleRouter.sol';
import './interfaces/IERC20.sol';
import './interfaces/IWETH.sol';
import './interfaces/IImpossibleWrappedToken.sol';
import './interfaces/IImpossibleWrapperFactory.sol';

/**
    @title  Router for Impossible Swap V3
    @author Impossible Finance
    @notice This router builds upon basic Uni V2 Router02 by allowing custom
            calculations based on settings in pairs (uni/xybk/custom fees)
    @dev    See documentation at: https://docs.impossible.finance/impossible-swap/overview
    @dev    Very little logical changes made in Router02. Most changes to accomodate xybk are in Library
*/

contract ImpossibleRouter is IImpossibleRouter, ReentrancyGuard {
    using SafeMath for uint256;

    address public immutable override factory;
    address public immutable override wrapFactory;

    address private utilitySettingAdmin;

    address public override routerExtension; // Can be set by utility setting admin once only
    address public override WETH; // Can be set by utility setting admin once only

    modifier ensure(uint256 deadline) {
        require(deadline >= block.timestamp, 'ImpossibleRouter: EXPIRED');
        _;
    }

    /**
     @notice Constructor for IF Router
     @param _pairFactory Address of IF Pair Factory
     @param _wrapFactory Address of IF
     @param _utilitySettingAdmin Admin address allowed to set addresses of utility contracts (once)
    */
    constructor(
        address _pairFactory,
        address _wrapFactory,
        address _utilitySettingAdmin
    ) {
        factory = _pairFactory;
        wrapFactory = _wrapFactory;
        utilitySettingAdmin = _utilitySettingAdmin;
    }

    receive() external payable {
        assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract
    }

    /**
     @notice Used to set addresses of utility contracts
     @dev Only allows setter to set these addresses once for trustlessness
     @dev Must set both WETH and routerExtension at the same time, else swap will be bricked
     @param _WETH address of WETH contract
     @param _routerExtension address of router interface contract
     */
    function setUtilities(address _WETH, address _routerExtension) public {
        require(WETH == address(0x0) && routerExtension == address(0x0));
        require(msg.sender == utilitySettingAdmin, 'IF: ?');
        WETH = _WETH;
        routerExtension = _routerExtension;
    }

    /**
     @notice Helper function for sending tokens that might need to be wrapped
     @param token The address of the token that might have a wrapper
     @param src The source to take underlying tokens from
     @param dst The destination to send wrapped tokens to
     @param amt The amount of tokens to send (wrapped tokens, not underlying)
    */
    function wrapSafeTransfer(
        address token,
        address src,
        address dst,
        uint256 amt
    ) internal {
        address underlying = IImpossibleWrapperFactory(wrapFactory).wrappedTokensToTokens(token);
        if (underlying == address(0x0)) {
            TransferHelper.safeTransferFrom(token, src, dst, amt);
        } else {
            uint256 underlyingAmt = IImpossibleWrappedToken(token).amtToUnderlyingAmt(amt);
            TransferHelper.safeTransferFrom(underlying, src, address(this), underlyingAmt);
            TransferHelper.safeApprove(underlying, token, underlyingAmt);
            IImpossibleWrappedToken(token).deposit(dst, underlyingAmt);
        }
    }

    /**
     @notice Helper function for sending tokens that might need to be unwrapped
     @param token The address of the token that might be wrapped
     @param dst The destination to send underlying tokens to
     @param amt The amount of wrapped tokens to send (wrapped tokens, not underlying)
    */
    function unwrapSafeTransfer(
        address token,
        address dst,
        uint256 amt
    ) internal {
        address underlying = IImpossibleWrapperFactory(wrapFactory).wrappedTokensToTokens(token);
        if (underlying == address(0x0)) {
            TransferHelper.safeTransfer(token, dst, amt);
        } else {
            IImpossibleWrappedToken(token).withdraw(dst, amt);
        }
    }

    /**
     @notice Swap function - receive maximum output given fixed input
     @dev Openzeppelin reentrancy guards
     @param amountIn The exact input amount`
     @param amountOutMin The minimum output amount allowed for a successful swap
     @param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
     @param to The address that receives the output tokens
     @param deadline The block number after which this transaction is invalid
     @return amounts Array of actual output token amounts received per swap, sequentially.
    */
    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external virtual override ensure(deadline) nonReentrant returns (uint256[] memory amounts) {
        amounts = ImpossibleLibrary.getAmountsOut(factory, amountIn, path);
        require(amounts[amounts.length - 1] >= amountOutMin, 'ImpossibleRouter: INSUFFICIENT_OUTPUT_AMOUNT');
        wrapSafeTransfer(path[0], msg.sender, ImpossibleLibrary.pairFor(factory, path[0], path[1]), amounts[0]);
        IImpossibleRouterExtension(routerExtension).swap(amounts, path);
        unwrapSafeTransfer(path[path.length - 1], to, amounts[amounts.length - 1]);
    }

    /**
     @notice Swap function - receive desired output amount given a maximum input amount
     @dev Openzeppelin reentrancy guards
     @param amountOut The exact output amount desired
     @param amountInMax The maximum input amount allowed for a successful swap
     @param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
     @param to The address that receives the output tokens
     @param deadline The block number after which this transaction is invalid
     @return amounts Array of actual output token amounts received per swap, sequentially.
    */
    function swapTokensForExactTokens(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external virtual override ensure(deadline) nonReentrant returns (uint256[] memory amounts) {
        amounts = ImpossibleLibrary.getAmountsIn(factory, amountOut, path);
        require(amounts[0] <= amountInMax, 'ImpossibleRouter: EXCESSIVE_INPUT_AMOUNT');
        wrapSafeTransfer(path[0], msg.sender, ImpossibleLibrary.pairFor(factory, path[0], path[1]), amounts[0]);
        IImpossibleRouterExtension(routerExtension).swap(amounts, path);
        unwrapSafeTransfer(path[path.length - 1], to, amountOut);
    }

    /**
     @notice Swap function - receive maximum output given fixed input of ETH
     @dev Openzeppelin reentrancy guards
     @param amountOutMin The minimum output amount allowed for a successful swap
     @param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
     @param to The address that receives the output tokens
     @param deadline The block number after which this transaction is invalid
     @return amounts Array of actual output token amounts received per swap, sequentially.
    */
    function swapExactETHForTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable virtual override ensure(deadline) nonReentrant returns (uint256[] memory amounts) {
        require(path[0] == WETH, 'ImpossibleRouter: INVALID_PATH');
        amounts = ImpossibleLibrary.getAmountsOut(factory, msg.value, path);
        require(amounts[amounts.length - 1] >= amountOutMin, 'ImpossibleRouter: INSUFFICIENT_OUTPUT_AMOUNT');
        IWETH(WETH).deposit{value: amounts[0]}();
        assert(IWETH(WETH).transfer(ImpossibleLibrary.pairFor(factory, path[0], path[1]), amounts[0]));
        IImpossibleRouterExtension(routerExtension).swap(amounts, path);
        unwrapSafeTransfer(path[path.length - 1], to, amounts[amounts.length - 1]);
    }

    /**
    @notice Swap function - receive desired ETH output amount given a maximum input amount
     @dev Openzeppelin reentrancy guards
     @param amountOut The exact output amount desired
     @param amountInMax The maximum input amount allowed for a successful swap
     @param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
     @param to The address that receives the output tokens
     @param deadline The block number after which this transaction is invalid
     @return amounts Array of actual output token amounts received per swap, sequentially.
    */
    function swapTokensForExactETH(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external virtual override ensure(deadline) nonReentrant returns (uint256[] memory amounts) {
        require(path[path.length - 1] == WETH, 'ImpossibleRouter: INVALID_PATH');
        amounts = ImpossibleLibrary.getAmountsIn(factory, amountOut, path);
        require(amounts[0] <= amountInMax, 'ImpossibleRouter: EXCESSIVE_INPUT_AMOUNT');
        wrapSafeTransfer(path[0], msg.sender, ImpossibleLibrary.pairFor(factory, path[0], path[1]), amounts[0]);
        IImpossibleRouterExtension(routerExtension).swap(amounts, path);
        IWETH(WETH).withdraw(amounts[amounts.length - 1]);
        TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
    }

    /**
     @notice Swap function - receive maximum ETH output given fixed input of tokens
     @dev Openzeppelin reentrancy guards
     @param amountIn The amount of input tokens
     @param amountOutMin The minimum ETH output amount required for successful swaps
     @param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
     @param to The address that receives the output tokens
     @param deadline The block number after which this transaction is invalid
     @return amounts Array of actual output token amounts received per swap, sequentially.
    */
    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external virtual override ensure(deadline) nonReentrant returns (uint256[] memory amounts) {
        require(path[path.length - 1] == WETH, 'ImpossibleRouter: INVALID_PATH');
        amounts = ImpossibleLibrary.getAmountsOut(factory, amountIn, path);
        require(amounts[amounts.length - 1] >= amountOutMin, 'ImpossibleRouter: INSUFFICIENT_OUTPUT_AMOUNT');
        wrapSafeTransfer(path[0], msg.sender, ImpossibleLibrary.pairFor(factory, path[0], path[1]), amounts[0]);
        IImpossibleRouterExtension(routerExtension).swap(amounts, path);
        IWETH(WETH).withdraw(amounts[amounts.length - 1]);
        TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
    }

    /**
     @notice Swap function - receive maximum tokens output given fixed ETH input
     @dev Openzeppelin reentrancy guards
     @param amountOut The minimum output amount in tokens required for successful swaps
     @param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
     @param to The address that receives the output tokens
     @param deadline The block number after which this transaction is invalid
     @return amounts Array of actual output token amounts received per swap, sequentially.
    */
    function swapETHForExactTokens(
        uint256 amountOut,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable virtual override ensure(deadline) nonReentrant returns (uint256[] memory amounts) {
        require(path[0] == WETH, 'ImpossibleRouter: INVALID_PATH');
        amounts = ImpossibleLibrary.getAmountsIn(factory, amountOut, path);
        require(amounts[0] <= msg.value, 'ImpossibleRouter: EXCESSIVE_INPUT_AMOUNT');
        IWETH(WETH).deposit{value: amounts[0]}();
        assert(IWETH(WETH).transfer(ImpossibleLibrary.pairFor(factory, path[0], path[1]), amounts[0]));
        IImpossibleRouterExtension(routerExtension).swap(amounts, path);
        unwrapSafeTransfer(path[path.length - 1], to, amountOut);
        // refund dust eth, if any
        if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
    }

    /**
     @notice Swap function for fee on transfer tokens, no WETH/WBNB
     @param amountIn The amount of input tokens
     @param amountOutMin The minimum token output amount required for successful swaps
     @param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
     @param to The address that receives the output tokens
     @param deadline The block number after which this transaction is invalid
    */
    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external virtual override ensure(deadline) nonReentrant {
        wrapSafeTransfer(path[0], msg.sender, ImpossibleLibrary.pairFor(factory, path[0], path[1]), amountIn);
        IImpossibleRouterExtension(routerExtension).swapSupportingFeeOnTransferTokens(path);
        uint256 balance = IERC20(path[path.length - 1]).balanceOf(address(this));
        require(balance >= amountOutMin, 'ImpossibleRouter: INSUFFICIENT_OUTPUT_AMOUNT');
        unwrapSafeTransfer(path[path.length - 1], to, balance);
    }

    /**
     @notice Swap function for fee on transfer tokens with WETH/WBNB
     @param amountOutMin The minimum underlying token output amount required for successful swaps
     @param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
     @param to The address that receives the output tokens
     @param deadline The block number after which this transaction is invalid
    */
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable virtual override ensure(deadline) nonReentrant {
        require(path[0] == WETH, 'ImpossibleRouter: INVALID_PATH');
        uint256 amountIn = msg.value;
        IWETH(WETH).deposit{value: amountIn}();
        assert(IWETH(WETH).transfer(ImpossibleLibrary.pairFor(factory, path[0], path[1]), amountIn));
        IImpossibleRouterExtension(routerExtension).swapSupportingFeeOnTransferTokens(path);
        uint256 balance = IERC20(path[path.length - 1]).balanceOf(address(this));
        require(balance >= amountOutMin, 'ImpossibleRouter: INSUFFICIENT_OUTPUT_AMOUNT');
        unwrapSafeTransfer(path[path.length - 1], to, balance);
    }

    /**
     @notice Swap function for fee on transfer tokens, no WETH/WBNB
     @param amountIn The amount of input tokens
     @param amountOutMin The minimum ETH output amount required for successful swaps
     @param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
     @param to The address that receives the output tokens
     @param deadline The block number after which this transaction is invalid
    */
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external virtual override ensure(deadline) nonReentrant {
        require(path[path.length - 1] == WETH, 'ImpossibleRouter: INVALID_PATH');
        wrapSafeTransfer(path[0], msg.sender, ImpossibleLibrary.pairFor(factory, path[0], path[1]), amountIn);
        IImpossibleRouterExtension(routerExtension).swapSupportingFeeOnTransferTokens(path);
        uint256 amountOut = IERC20(WETH).balanceOf(address(this));
        require(amountOut >= amountOutMin, 'ImpossibleRouter: INSUFFICIENT_OUTPUT_AMOUNT');
        IWETH(WETH).withdraw(amountOut);
        TransferHelper.safeTransferETH(to, amountOut);
    }

    /**
     @notice Function for basic add liquidity functionality
     @dev Openzeppelin reentrancy guards
     @param tokenA The address of underlying tokenA to add
     @param tokenB The address of underlying tokenB to add
     @param amountADesired The desired amount of tokenA to add
     @param amountBDesired The desired amount of tokenB to add
     @param amountAMin The min amount of tokenA to add (amountAMin:amountBDesired sets bounds on ratio)
     @param amountBMin The min amount of tokenB to add (amountADesired:amountBMin sets bounds on ratio)
     @param to The address to mint LP tokens to
     @param deadline The block number after which this transaction is invalid
     @return amountA Amount of tokenA added as liquidity to pair
     @return amountB Actual amount of tokenB added as liquidity to pair
     @return liquidity Actual amount of LP tokens minted
    */
    function addLiquidity(
        address tokenA,
        address tokenB,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    )
        external
        virtual
        override
        ensure(deadline)
        nonReentrant
        returns (
            uint256 amountA,
            uint256 amountB,
            uint256 liquidity
        )
    {
        (amountA, amountB) = IImpossibleRouterExtension(routerExtension).addLiquidity(
            tokenA,
            tokenB,
            amountADesired,
            amountBDesired,
            amountAMin,
            amountBMin
        );
        address pair = ImpossibleLibrary.pairFor(factory, tokenA, tokenB);
        wrapSafeTransfer(tokenA, msg.sender, pair, amountA);
        wrapSafeTransfer(tokenB, msg.sender, pair, amountB);
        liquidity = IImpossiblePair(pair).mint(to);
    }

    /**
     @notice Function for add liquidity functionality with 1 token being WETH/WBNB
     @dev Openzeppelin reentrancy guards
     @param token The address of the non-ETH underlying token to add
     @param amountTokenDesired The desired amount of non-ETH underlying token to add
     @param amountTokenMin The min amount of non-ETH underlying token to add (amountTokenMin:ETH sent sets bounds on ratio)
     @param amountETHMin The min amount of WETH/WBNB to add (amountTokenDesired:amountETHMin sets bounds on ratio)
     @param to The address to mint LP tokens to
     @param deadline The block number after which this transaction is invalid
     @return amountToken Amount of non-ETH underlying token added as liquidity to pair
     @return amountETH Actual amount of WETH/WBNB added as liquidity to pair
     @return liquidity Actual amount of LP tokens minted
    */
    function addLiquidityETH(
        address token,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    )
        external
        payable
        virtual
        override
        ensure(deadline)
        nonReentrant
        returns (
            uint256 amountToken,
            uint256 amountETH,
            uint256 liquidity
        )
    {
        (amountToken, amountETH) = IImpossibleRouterExtension(routerExtension).addLiquidity(
            token,
            WETH,
            amountTokenDesired,
            msg.value,
            amountTokenMin,
            amountETHMin
        );
        address pair = ImpossibleLibrary.pairFor(factory, token, WETH);
        wrapSafeTransfer(token, msg.sender, pair, amountToken);
        IWETH(WETH).deposit{value: amountETH}();
        assert(IWETH(WETH).transfer(pair, amountETH));
        liquidity = IImpossiblePair(pair).mint(to);
        if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH); // refund dust eth, if any
    }

    /**
     @notice Function for basic remove liquidity functionality
     @dev Openzeppelin reentrancy guards
     @param tokenA The address of underlying tokenA in LP token
     @param tokenB The address of underlying tokenB in LP token
     @param liquidity The amount of LP tokens to burn
     @param amountAMin The min amount of underlying tokenA that has to be received
     @param amountBMin The min amount of underlying tokenB that has to be received
     @param to The address to send underlying tokens to
     @param deadline The block number after which this transaction is invalid
     @return amountA Actual amount of underlying tokenA received
     @return amountB Actual amount of underlying tokenB received
    */
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) public virtual override ensure(deadline) nonReentrant returns (uint256 amountA, uint256 amountB) {
        address pair = ImpossibleLibrary.pairFor(factory, tokenA, tokenB);
        IImpossiblePair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
        (amountA, amountB) = IImpossibleRouterExtension(routerExtension).removeLiquidity(
            tokenA,
            tokenB,
            pair,
            amountAMin,
            amountBMin
        );
        unwrapSafeTransfer(tokenA, to, amountA);
        unwrapSafeTransfer(tokenB, to, amountB);
    }

    /**
     @notice Function for remove liquidity functionality with 1 token being WETH/WBNB
     @dev Openzeppelin reentrancy guards
     @param token The address of the non-ETH underlying token to receive
     @param liquidity The amount of LP tokens to burn
     @param amountTokenMin The desired amount of non-ETH underlying token that has to be received
     @param amountETHMin The min amount of ETH that has to be received
     @param to The address to send underlying tokens to
     @param deadline The block number after which this transaction is invalid
     @return amountToken Actual amount of non-ETH underlying token received
     @return amountETH Actual amount of WETH/WBNB received
    */
    function removeLiquidityETH(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) public virtual override ensure(deadline) nonReentrant returns (uint256 amountToken, uint256 amountETH) {
        address pair = ImpossibleLibrary.pairFor(factory, token, WETH);
        IImpossiblePair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
        (amountToken, amountETH) = IImpossibleRouterExtension(routerExtension).removeLiquidity(
            token,
            WETH,
            pair,
            amountTokenMin,
            amountETHMin
        );
        unwrapSafeTransfer(token, to, amountToken);
        IWETH(WETH).withdraw(amountETH);
        TransferHelper.safeTransferETH(to, amountETH);
    }

    /**
    @notice Function for remove liquidity functionality using EIP712 permit
     @dev Openzeppelin reentrancy guards
     @param tokenA The address of underlying tokenA in LP token
     @param tokenB The address of underlying tokenB in LP token
     @param liquidity The amount of LP tokens to burn
     @param amountAMin The min amount of underlying tokenA that has to be received
     @param amountBMin The min amount of underlying tokenB that has to be received
     @param to The address to send underlying tokens to
     @param deadline The block number after which this transaction is invalid
     @param approveMax How much tokens are approved for transfer (liquidity, or max)
     @param v,r,s Variables that construct a valid EVM signature
     @return amountA Actual amount of underlying tokenA received
     @return amountB Actual amount of underlying tokenB received
    */
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external virtual override returns (uint256 amountA, uint256 amountB) {
        address pair = ImpossibleLibrary.pairFor(factory, tokenA, tokenB);
        uint256 value = approveMax ? uint256(-1) : liquidity;
        IImpossiblePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
        return removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
    }

    /**
     @notice Function for remove liquidity functionality using EIP712 permit with 1 token being WETH/WBNB
     @param token The address of the non-ETH underlying token to receive
     @param liquidity The amount of LP tokens to burn
     @param amountTokenMin The desired amount of non-ETH underlying token that has to be received
     @param amountETHMin The min amount of ETH that has to be received
     @param to The address to send underlying tokens to
     @param deadline The block number after which this transaction is invalid
     @param approveMax How much tokens are approved for transfer (liquidity, or max)
     @param v,r,s Variables that construct a valid EVM signature
     @return amountToken Actual amount of non-ETH underlying token received
     @return amountETH Actual amount of WETH/WBNB received
    */
    function removeLiquidityETHWithPermit(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external virtual override returns (uint256 amountToken, uint256 amountETH) {
        address pair = ImpossibleLibrary.pairFor(factory, token, WETH);
        uint256 value = approveMax ? uint256(-1) : liquidity;
        IImpossiblePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
        (amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
    }

    /**
     @notice Function for remove liquidity functionality with 1 token being WETH/WBNB
     @dev This is used when non-WETH/WBNB underlying token is fee-on-transfer: e.g. FEI algo stable v1
     @dev Openzeppelin reentrancy guards
     @param token The address of the non-ETH underlying token to receive
     @param liquidity The amount of LP tokens to burn
     @param amountTokenMin The desired amount of non-ETH underlying token that has to be received
     @param amountETHMin The min amount of ETH that has to be received
     @param to The address to send underlying tokens to
     @param deadline The block number after which this transaction is invalid
     @return amountETH Actual amount of WETH/WBNB received
    */
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) public virtual override ensure(deadline) nonReentrant returns (uint256 amountETH) {
        address pair = ImpossibleLibrary.pairFor(factory, token, WETH);
        IImpossiblePair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
        (, amountETH) = IImpossibleRouterExtension(routerExtension).removeLiquidity(
            token,
            WETH,
            pair,
            amountTokenMin,
            amountETHMin
        );
        unwrapSafeTransfer(token, to, IERC20(token).balanceOf(address(this)));
        IWETH(WETH).withdraw(amountETH);
        TransferHelper.safeTransferETH(to, amountETH);
    }

    /**
     @notice Function for remove liquidity functionality using EIP712 permit with 1 token being WETH/WBNB
     @dev This is used when non-WETH/WBNB underlying token is fee-on-transfer: e.g. FEI algo stable v1
     @param token The address of the non-ETH underlying token to receive
     @param liquidity The amount of LP tokens to burn
     @param amountTokenMin The desired amount of non-ETH underlying token that has to be received
     @param amountETHMin The min amount of ETH that has to be received
     @param to The address to send underlying tokens to
     @param deadline The block number after which this transaction is invalid
     @param approveMax How much tokens are approved for transfer (liquidity, or max)
     @param v,r,s Variables that construct a valid EVM signature
     @return amountETH Actual amount of WETH/WBNB received
    */
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external virtual override returns (uint256 amountETH) {
        address pair = ImpossibleLibrary.pairFor(factory, token, WETH);
        uint256 value = approveMax ? uint256(-1) : liquidity;
        IImpossiblePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
        amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(
            token,
            liquidity,
            amountTokenMin,
            amountETHMin,
            to,
            deadline
        );
    }
}

File 23 of 24 : IImpossibleRouter.sol
// SPDX-License-Identifier: GPL-3
pragma solidity >=0.6.2;

interface IImpossibleRouter {
    function factory() external view returns (address factoryAddr);

    function routerExtension() external view returns (address routerExtensionAddr);

    function wrapFactory() external view returns (address wrapFactoryAddr);

    function WETH() external view returns (address WETHAddr);

    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapTokensForExactTokens(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapExactETHForTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function swapTokensForExactETH(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapETHForExactTokens(
        uint256 amountOut,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;

    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable;

    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    )
        external
        returns (
            uint256 amountA,
            uint256 amountB,
            uint256 liquidity
        );

    function addLiquidityETH(
        address token,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    )
        external
        payable
        returns (
            uint256 amountToken,
            uint256 amountETH,
            uint256 liquidity
        );

    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB);

    function removeLiquidityETH(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountToken, uint256 amountETH);

    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountA, uint256 amountB);

    function removeLiquidityETHWithPermit(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountToken, uint256 amountETH);

    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountETH);

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

File 24 of 24 : IWETH.sol
// SPDX-License-Identifier: GPL-3
pragma solidity >=0.5.0;

interface IWETH {
    function deposit() external payable;

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

    function withdraw(uint256) external;
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  }
}

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":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"_isXybk","type":"bool"},{"indexed":false,"internalType":"uint256","name":"_newBoost0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newBoost1","type":"uint256"}],"name":"ChangeInvariant","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":"amount0In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount0Out","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1Out","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reserve0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reserve1","type":"uint256"}],"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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"_oldBoost0","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"_oldBoost1","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"_newBoost0","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"_newBoost1","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"_start","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_end","type":"uint256"}],"name":"UpdatedBoost","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_oldDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newDelay","type":"uint256"}],"name":"UpdatedDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newFee","type":"uint256"}],"name":"UpdatedTradeFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum IImpossiblePair.TradeState","name":"_tradeState","type":"uint8"}],"name":"UpdatedTradeState","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_oldWithdrawalFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newWithdrawalFee","type":"uint256"}],"name":"UpdatedWithdrawalFeeRatio","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_LIQUIDITY","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":[{"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":"to","type":"address"}],"name":"burn","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"calcBoost","outputs":[{"internalType":"uint256","name":"_boost0","type":"uint256"},{"internalType":"uint256","name":"_boost1","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPairSettings","outputs":[{"internalType":"uint16","name":"_tradeFee","type":"uint16"},{"internalType":"enum IImpossiblePair.TradeState","name":"_tradeState","type":"uint8"},{"internalType":"bool","name":"_isXybk","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint256","name":"_reserve0","type":"uint256"},{"internalType":"uint256","name":"_reserve1","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token0","type":"address"},{"internalType":"address","name":"_token1","type":"address"},{"internalType":"address","name":"_router","type":"address"},{"internalType":"address","name":"_routerExtension","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"kLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"makeUni","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_newBoost0","type":"uint32"},{"internalType":"uint32","name":"_newBoost1","type":"uint32"}],"name":"makeXybk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","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":[],"name":"router","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"routerExtension","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"skim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount0Out","type":"uint256"},{"internalType":"uint256","name":"amount1Out","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swap","outputs":[],"stateMutability":"nonpayable","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"},{"inputs":[{"internalType":"uint32","name":"_newBoost0","type":"uint32"},{"internalType":"uint32","name":"_newBoost1","type":"uint32"}],"name":"updateBoost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newDelay","type":"uint256"}],"name":"updateDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_newFee","type":"uint8"}],"name":"updateTradeFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IImpossiblePair.TradeState","name":"_tradeState","type":"uint8"}],"name":"updateTradeState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newFeeRatio","type":"uint256"}],"name":"updateWithdrawalFeeRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalFeeRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60c0604052601360808190527f496d706f737369626c652053776170204c50730000000000000000000000000060a090815262000040916000919062000250565b5060408051808201909152600580825264049462d4c560dc1b60209092019182526200006f9160019162000250565b506008805461ffff1916601e179055600f805463ffffffff60a01b1963ffffffff60801b1963ffffffff60601b1963ffffffff60401b1963ffffffff60201b1963ffffffff199095166001179490941664010000000017939093166801000000000000000017929092166c010000000000000000000000001791909116600160801b1716600160a01b17905560c9601255620151806013553480156200011457600080fd5b506200011f62000146565b600160075560088054600160201b600160c01b0319163364010000000002179055620002fc565b60004690507f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040518082805460018160011615610100020316600290048015620001cd5780601f10620001aa576101008083540402835291820191620001cd565b820191906000526020600020905b815481529060010190602001808311620001b8575b505060408051918290038220828201825260018352603160f81b602093840152815180840196909652858201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606086015260808501959095523060a0808601919091528551808603909101815260c090940190945250508051910120600555565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282620002885760008555620002d3565b82601f10620002a357805160ff1916838001178555620002d3565b82800160010185558215620002d3579182015b82811115620002d3578251825591602001919060010190620002b6565b50620002e1929150620002e5565b5090565b5b80821115620002e15760008155600101620002e6565b613d5b806200030c6000396000f3fe608060405234801561001057600080fd5b50600436106102485760003560e01c80637464fc3d1161013b578063c45a0155116100b8578063dd62ed3e1161007c578063dd62ed3e146106c4578063e94e3d8d146106f2578063f887ea401461072f578063f8c8765e14610737578063fff6cae91461077557610248565b8063c45a015514610626578063d1b2664f1461062e578063d21220a71461064b578063d4f0a77714610653578063d505accf1461067357610248565b8063a9059cbb116100ff578063a9059cbb14610599578063b6b9f61b146105c5578063ba9a7a56146105cd578063bb3a19a4146105d5578063bc25cf771461060057610248565b80637464fc3d1461053557806378e979251461053d5780637ecebe001461054557806389afcb441461056b57806395d89b411461059157610248565b8063313ce567116101c95780635de879701161018d5780635de87970146104bc57806364d62353146104c45780636a42b8f8146104e15780636a627842146104e957806370a082311461050f57610248565b8063313ce5671461047e5780633197cbb61461049c57806334762d09146104a45780633644e515146104ac578063590c61f0146104b457610248565b8063112db51b11610210578063112db51b146103db57806315fc3d92146103fb57806318160ddd1461042657806323b872dd1461044057806330adf81f1461047657610248565b8063022c0d9f1461024d57806306fdde03146102d95780630902f1ac14610356578063095ea7b3146103775780630dfe1681146103b7575b600080fd5b6102d76004803603608081101561026357600080fd5b8135916020810135916001600160a01b036040830135169190810190608081016060820135600160201b81111561029957600080fd5b8201836020820111156102ab57600080fd5b803590602001918460018302840111600160201b831117156102cc57600080fd5b50909250905061077d565b005b6102e1610e3d565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561031b578181015183820152602001610303565b50505050905090810190601f1680156103485780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61035e610ecb565b6040805192835260208301919091528051918290030190f35b6103a36004803603604081101561038d57600080fd5b506001600160a01b038135169060200135610ee6565b604080519115158252519081900360200190f35b6103bf610efd565b604080516001600160a01b039092168252519081900360200190f35b6102d7600480360360208110156103f157600080fd5b503560ff16610f0c565b6102d76004803603604081101561041157600080fd5b5063ffffffff813581169160200135166110de565b61042e6112bc565b60408051918252519081900360200190f35b6103a36004803603606081101561045657600080fd5b506001600160a01b038135811691602081013590911690604001356112c2565b61042e611357565b61048661137b565b6040805160ff9092168252519081900360200190f35b61042e611380565b6102d7611386565b61042e611650565b6103bf611656565b61042e611665565b6102d7600480360360208110156104da57600080fd5b503561166b565b61042e6117d5565b61042e600480360360208110156104ff57600080fd5b50356001600160a01b03166117db565b61042e6004803603602081101561052557600080fd5b50356001600160a01b0316611ac8565b61042e611ada565b61042e611ae0565b61042e6004803603602081101561055b57600080fd5b50356001600160a01b0316611ae6565b61035e6004803603602081101561058157600080fd5b50356001600160a01b0316611af8565b6102e1611ff5565b6103a3600480360360408110156105af57600080fd5b506001600160a01b03813516906020013561204f565b61035e61205c565b61042e6120fa565b6102d7600480360360408110156105eb57600080fd5b5063ffffffff81358116916020013516612100565b6102d76004803603602081101561061657600080fd5b50356001600160a01b0316612279565b6103bf6123d5565b6102d76004803603602081101561064457600080fd5b50356123eb565b6103bf612540565b6102d76004803603602081101561066957600080fd5b503560ff1661254f565b6102d7600480360360e081101561068957600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c0013561266d565b61042e600480360360408110156106da57600080fd5b506001600160a01b0381358116916020013516612860565b6106fa61287d565b604051808461ffff16815260200183600381111561071457fe5b81526020018215158152602001935050505060405180910390f35b6103bf61289c565b6102d76004803603608081101561074d57600080fd5b506001600160a01b0381358116916020810135821691604082013581169160600135166128ab565b6102d761295b565b600b546001600160a01b03163314806107a05750600c546001600160a01b031633145b6107e1576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b60026007541415610827576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b60026007558415158061083a5750600084115b61088b576040805162461bcd60e51b815260206004820152601e60248201527f49463a20494e53554646494349454e545f4f55545055545f414d4f554e540000604482015290519081900360640190fd5b600080610896610ecb565b915091508187111580156108aa5750808611155b6108fb576040805162461bcd60e51b815260206004820152601a60248201527f49463a20494e53554646494349454e545f4c4951554944495459000000000000604482015290519081900360640190fd5b6009546000908190819081906001600160a01b038a81169116148015906109305750600a546001600160a01b038a8116911614155b610972576040805162461bcd60e51b815260206004820152600e60248201526d49463a20494e56414c49445f544f60901b604482015290519081900360640190fd5b8a1561098f5760095461098f906001600160a01b03168a8d612aa6565b89156109ac57600a546109ac906001600160a01b03168a8c612aa6565b8615610a5e57886001600160a01b03166367e95e6f338d8d8c8c6040518663ffffffff1660e01b815260040180866001600160a01b03168152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b158015610a4557600080fd5b505af1158015610a59573d6000803e3d6000fd5b505050505b600954604080516370a0823160e01b815230600482015290516001600160a01b03909216916370a0823191602480820192602092909190829003018186803b158015610aa957600080fd5b505afa158015610abd573d6000803e3d6000fd5b505050506040513d6020811015610ad357600080fd5b5051600a54604080516370a0823160e01b815230600482015290519296506001600160a01b03909116916370a0823191602480820192602092909190829003018186803b158015610b2357600080fd5b505afa158015610b37573d6000803e3d6000fd5b505050506040513d6020811015610b4d57600080fd5b505192508a86038411610b61576000610b67565b8a860384035b91508985038311610b79576000610b7f565b89850383035b90506000821180610b905750600081115b610be1576040805162461bcd60e51b815260206004820152601d60248201527f49463a20494e53554646494349454e545f494e5055545f414d4f554e54000000604482015290519081900360640190fd5b60085460ff63010000008204169061ffff166000610c14610c028684612c35565b610c0e89612710612c35565b90612c98565b90506000610c25610c028685612c35565b90508315610d615760085462010000900460ff166000816003811115610c4757fe5b1480610c6757506001816003811115610c5c57fe5b148015610c6757508e155b80610c8657506002816003811115610c7b57fe5b148015610c8657508f155b610ccf576040805162461bcd60e51b815260206004820152601560248201527412518e88151490511157d393d517d0531313d5d151605a1b604482015290519081900360640190fd5b600080610cda61205c565b915091506000610cf86305f5e100610cf28585612ce8565b90612c35565b9050610d078383888885612d91565b610d58576040805162461bcd60e51b815260206004820152601760248201527f49463a20494e53554646494349454e545f5859424b5f4b000000000000000000604482015290519081900360640190fd5b50505050610dc9565b610d736305f5e100610cf28c8c612c35565b610d7d8383612c35565b1015610dc9576040805162461bcd60e51b815260206004820152601660248201527549463a20494e53554646494349454e545f554e495f4b60501b604482015290519081900360640190fd5b50505050610dd78484612e0b565b60408051838152602081018390528082018d9052606081018c905290516001600160a01b038b169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229181900360800190a350506001600755505050505050505050565b6000805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ec35780601f10610e9857610100808354040283529160200191610ec3565b820191906000526020600020905b815481529060010190602001808311610ea657829003601f168201915b505050505081565b600d546001600160801b0380821692600160801b9092041690565b6000610ef3338484612e8b565b5060015b92915050565b6009546001600160a01b031681565b600860049054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b158015610f5a57600080fd5b505afa158015610f6e573d6000803e3d6000fd5b505050506040513d6020811015610f8457600080fd5b50516001600160a01b03163314610fd2576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b60026007541415611018576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b60026007556008546301000000900460ff16611072576040805162461bcd60e51b815260206004820152601460248201527349463a2049535f43555252454e544c595f554e4960601b604482015290519081900360640190fd5b6008805482919062ff000019166201000083600381111561108f57fe5b02179055507f804ede6198c4ba5ac5c2ab3c86f51a6418ba3592262bf932bc9cbe6a18e4c79981604051808260038111156110c657fe5b815260200191505060405180910390a1506001600755565b600860049054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b15801561112c57600080fd5b505afa158015611140573d6000803e3d6000fd5b505050506040513d602081101561115657600080fd5b50516001600160a01b031633146111a4576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b600260075414156111ea576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b60026007556008546301000000900460ff1615611244576040805162461bcd60e51b815260206004820152601360248201527249463a2049535f414c52454144595f5859424b60681b604482015290519081900360640190fd5b61124e8282612eed565b6008805463ff0000001916630100000090811791829055604080519190920460ff161515815263ffffffff808516602083015283168183015290517fe81694441e8badb2a6bd046b401e64e8775f8055523d0263c9948f4a5b8026b39181900360600190a150506001600755565b60025481565b6001600160a01b038316600090815260046020908152604080832033845290915281205460001914611341576001600160a01b038416600090815260046020908152604080832033845290915290205461131c9083612c98565b6001600160a01b03851660009081526004602090815260408083203384529091529020555b61134c8484846130d1565b5060015b9392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b60115481565b600860049054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b1580156113d457600080fd5b505afa1580156113e8573d6000803e3d6000fd5b505050506040513d60208110156113fe57600080fd5b50516001600160a01b0316331461144c576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b60026007541415611492576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b60026007556008546301000000900460ff166114ea576040805162461bcd60e51b815260206004820152601260248201527149463a2049535f414c52454144595f554e4960701b604482015290519081900360640190fd5b601154421015611541576040805162461bcd60e51b815260206004820152601a60248201527f49463a20424f4f53545f414c52454144595f4348414e47494e47000000000000604482015290519081900360640190fd5b600f54600160401b900463ffffffff16600114801561156f5750600f54600160601b900463ffffffff166001145b6115b4576040805162461bcd60e51b815260206004820152601160248201527012518e881253959053125117d093d3d4d5607a1b604482015290519081900360640190fd5b6008805463ff000000191690819055600f805467ffffffff000000001963ffffffff1990911660011716600160201b179081905560408051630100000090930460ff1615158352600160401b820463ffffffff9081166020850152600160601b90920490911682820152517fe81694441e8badb2a6bd046b401e64e8775f8055523d0263c9948f4a5b8026b39181900360600190a16001600755565b60055481565b600c546001600160a01b031681565b60125481565b600860049054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b1580156116b957600080fd5b505afa1580156116cd573d6000803e3d6000fd5b505050506040513d60208110156116e357600080fd5b50516001600160a01b03163314611731576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b6201a5e0811015801561174957506013546212750010155b61178e576040805162461bcd60e51b815260206004820152601160248201527049463a20494e56414c49445f44454c415960781b604482015290519081900360640190fd5b6013805490829055604080518281526020810184905281517f40abb331f787260ef2fdd0c9e0ecc9bf68758a43190094281842f10ffcc318b2929181900390910190a15050565b60135481565b600060026007541415611823576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b6002600755600080611833610ecb565b600954604080516370a0823160e01b815230600482015290519395509193506000926001600160a01b03909116916370a08231916024808301926020929190829003018186803b15801561188657600080fd5b505afa15801561189a573d6000803e3d6000fd5b505050506040513d60208110156118b057600080fd5b5051600a54604080516370a0823160e01b815230600482015290519293506000926001600160a01b03909216916370a0823191602480820192602092909190829003018186803b15801561190357600080fd5b505afa158015611917573d6000803e3d6000fd5b505050506040513d602081101561192d57600080fd5b50519050600061193d8386612c98565b9050600061194b8386612c98565b90506000611959878761317f565b600254909150806119905761197c6103e8610c0e6119778787612c35565b6132ee565b985061198b60006103e8613340565b6119e3565b6119e0600089116119a3576000196119b7565b886119ae8684612c35565b816119b557fe5b045b600089116119c7576000196119db565b886119d28685612c35565b816119d957fe5b045b6133cb565b98505b60008911611a225760405162461bcd60e51b8152600401808060200182810382526021815260200180613ce46021913960400191505060405180910390fd5b611a2c8a8a613340565b611a368686612e0b565b600080611a416133e1565b915091508315611a79576008546301000000900460ff16611a6b57611a668888612c35565b611a75565b611a758282612ce8565b600e555b6040805187815260208101879052815133927f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f928290030190a250506001600755509698975050505050505050565b60036020526000908152604090205481565b600e5481565b60105481565b60066020526000908152604090205481565b60008060026007541415611b41576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b6002600755600080611b51610ecb565b915091506000611b61838361317f565b600954600a54604080516370a0823160e01b815230600482015290519394506001600160a01b0392831693919092169160009184916370a08231916024808301926020929190829003018186803b158015611bbb57600080fd5b505afa158015611bcf573d6000803e3d6000fd5b505050506040513d6020811015611be557600080fd5b5051604080516370a0823160e01b815230600482015290519192506000916001600160a01b038516916370a08231916024808301926020929190829003018186803b158015611c3357600080fd5b505afa158015611c47573d6000803e3d6000fd5b505050506040513d6020811015611c5d57600080fd5b5051306000908152600360205260409020546002549192509080611c818386612c35565b81611c8857fe5b049a5080611c968385612c35565b81611c9d57fe5b04995060008b1180611caf575060008a115b611cea5760405162461bcd60e51b8152600401808060200182810382526021815260200180613d056021913960400191505060405180910390fd5b6000600860049054906101000a90046001600160a01b03166001600160a01b031663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b158015611d3a57600080fd5b505afa158015611d4e573d6000803e3d6000fd5b505050506040513d6020811015611d6457600080fd5b50519050878015611d7e5750326001600160a01b03821614155b15611e4e57601254611d908d8261342d565b909c039b611d9e8c8261342d565b909b039a6000611dae858361342d565b9050611e3430600860049054906101000a90046001600160a01b03166001600160a01b031663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b158015611e0257600080fd5b505afa158015611e16573d6000803e3d6000fd5b505050506040513d6020811015611e2c57600080fd5b505183612aa6565b611e4730611e428784612c98565b61346f565b5050611e58565b611e58308461346f565b611e63878e8e612aa6565b611e6e868e8d612aa6565b5050604080516370a0823160e01b815230600482015290516001600160a01b038716916370a08231916024808301926020929190829003018186803b158015611eb657600080fd5b505afa158015611eca573d6000803e3d6000fd5b505050506040513d6020811015611ee057600080fd5b5051604080516370a0823160e01b815230600482015290519194506001600160a01b038616916370a0823191602480820192602092909190829003018186803b158015611f2c57600080fd5b505afa158015611f40573d6000803e3d6000fd5b505050506040513d6020811015611f5657600080fd5b50519150611f648383612e0b565b8515611f98576008546301000000900460ff16611f8a57611f858383612c35565b611f94565b611f948383612ce8565b600e555b604080518b8152602081018b905281516001600160a01b038e169233927fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496929081900390910190a350505050505050506001600781905550915091565b60018054604080516020600284861615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ec35780601f10610e9857610100808354040283529160200191610ec3565b6000610ef33384846130d1565b6000806000601154905080421061209157600080612078613500565b505063ffffffff938416985050501693506120f5915050565b6000806000806000806120a2613500565b9550955095509550955095506120b9848789613541565b98506120c6838689613541565b9750600e546120d58a8a612ce8565b10156120ee578163ffffffff1698508063ffffffff1697505b5050505050505b509091565b6103e881565b600860049054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b15801561214e57600080fd5b505afa158015612162573d6000803e3d6000fd5b505050506040513d602081101561217857600080fd5b50516001600160a01b031633146121c6576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b6002600754141561220c576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b60026007556008546301000000900460ff16612266576040805162461bcd60e51b815260206004820152601460248201527349463a2049535f43555252454e544c595f554e4960601b604482015290519081900360640190fd5b6122708282612eed565b50506001600755565b600260075414156122bf576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b6002600755600954600a546001600160a01b0391821691166000806122e2610ecb565b91509150612373848661236e85886001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561233c57600080fd5b505afa158015612350573d6000803e3d6000fd5b505050506040513d602081101561236657600080fd5b505190612c98565b612aa6565b6123c9838661236e84876001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561233c57600080fd5b50506001600755505050565b600854600160201b90046001600160a01b031681565b600860049054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b15801561243957600080fd5b505afa15801561244d573d6000803e3d6000fd5b505050506040513d602081101561246357600080fd5b50516001600160a01b031633146124b1576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b60648110156124f9576040805162461bcd60e51b815260206004820152600f60248201526e49463a20494e56414c49445f46454560881b604482015290519081900360640190fd5b6012805490829055604080518281526020810184905281517f985b27d3fed0c26bf4c91858b7a7bf9f3406337d65fcb519d177f56758627508929181900390910190a15050565b600a546001600160a01b031681565b600860049054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b15801561259d57600080fd5b505afa1580156125b1573d6000803e3d6000fd5b505050506040513d60208110156125c757600080fd5b50516001600160a01b03163314612615576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b6008805460ff831661ffff19821681179092556040805161ffff909216808352602083019390935280517f907af1ce671677e36d7827744cdc6febfa3a1124adfb2bfb5288e1ae9896dda29281900390910190a15050565b428410156126b0576040805162461bcd60e51b815260206004820152600b60248201526a12518e881156141254915160aa1b604482015290519081900360640190fd5b6005546001600160a01b0380891660008181526006602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e08501825280519083012061190160f01b6101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e280820193601f1981019281900390910190855afa1580156127cb573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906128015750886001600160a01b0316816001600160a01b0316145b61284a576040805162461bcd60e51b815260206004820152601560248201527449463a20494e56414c49445f5349474e415455524560581b604482015290519081900360640190fd5b612855898989612e8b565b505050505050505050565b600460209081526000928352604080842090915290825290205481565b60085461ffff81169160ff620100008304811692630100000090041690565b600b546001600160a01b031681565b600854600160201b90046001600160a01b03163314612901576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b600b80546001600160a01b038085166001600160a01b031992831617909255600c805484841690831617905560098054878416908316179055600a80549286169290911691909117905561295584846135e6565b50505050565b600260075414156129a1576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b6002600755600954604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b1580156129f157600080fd5b505afa158015612a05573d6000803e3d6000fd5b505050506040513d6020811015612a1b57600080fd5b5051600a54604080516370a0823160e01b815230600482015290519293506000926001600160a01b03909216916370a0823191602480820192602092909190829003018186803b158015612a6e57600080fd5b505afa158015612a82573d6000803e3d6000fd5b505050506040513d6020811015612a9857600080fd5b505190506122708282612e0b565b604080518082018252601981527f7472616e7366657228616464726573732c75696e74323536290000000000000060209182015281516001600160a01b0385811660248301526044808301869052845180840390910181526064909201845291810180516001600160e01b031663a9059cbb60e01b17815292518151600094859489169392918291908083835b60208310612b525780518252601f199092019160209182019101612b33565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612bb4576040519150601f19603f3d011682016040523d82523d6000602084013e612bb9565b606091505b5091509150818015612be7575080511580612be75750808060200190516020811015612be457600080fd5b50515b612c2e576040805162461bcd60e51b815260206004820152601360248201527212518e881514905394d1915497d19052531151606a1b604482015290519081900360640190fd5b5050505050565b6000811580612c5057505080820282828281612c4d57fe5b04145b610ef7576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604482015290519081900360640190fd5b80820382811115610ef7576040805162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b604482015290519081900360640190fd5b6000806000612cf5610ecb565b915091506000818311612d1257612d0d856001612c98565b612d1d565b612d1d866001612c98565b90506000612d376001612d31846002612c35565b90613a2b565b90506000612d63612d49836002612c35565b612d5d612d568888613a2b565b8690612c35565b9061342d565b9050600281612d83612d7985612d5d8a8a612c35565b6002850a016132ee565b010a98975050505050505050565b600080612d9d836132ee565b90506000848611612db857612db3876001612c98565b612dc3565b612dc3886001612c98565b90506000612dd18284612c35565b905084612dfc6002612de4856001613a2b565b0a612d5d612df28a86613a2b565b610cf28c87613a2b565b10159998505050505050505050565b600d80546fffffffffffffffffffffffffffffffff19166001600160801b03848116919091178116600160801b8483168102919091179283905560408051848416815291909304909116602082015281517fcf2aa50876cdfbb541206f89af0ee78d44a2abf8d328e37fa4917f982149848a929181900390910190a15050565b6001600160a01b03808416600081815260046020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b60018263ffffffff1610158015612f0b575060018163ffffffff1610155b8015612f205750620f42408263ffffffff1611155b8015612f355750620f42408163ffffffff1611155b612f7a576040805162461bcd60e51b815260206004820152601160248201527012518e881253959053125117d093d3d4d5607a1b604482015290519081900360640190fd5b6011544290811015612fd3576040805162461bcd60e51b815260206004820152601a60248201527f49463a20424f4f53545f414c52454144595f4348414e47494e47000000000000604482015290519081900360640190fd5b600080612fde610ecb565b91509150612fec828261317f565b50600f805467ffffffff0000000019600160401b80830463ffffffff90811663ffffffff1990941693909317918216600160601b928390048416600160201b908102919091176bffffffff000000000000000019168a851683021763ffffffff60601b191689851684021794859055601088905560135488016011819055604080518787168152928704861660208401529286048516828401529290940490921660608401526080830186905260a0830152517ff771495302afb2f84f43cab3d699e9548748b5154c0c8feba486d0e3e1d860799160c0908290030190a15050505050565b6001600160a01b0383166000908152600360205260409020546130f49082612c98565b6001600160a01b0380851660009081526003602052604080822093909355908416815220546131239082613a2b565b6001600160a01b0380841660008181526003602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600080600860049054906101000a90046001600160a01b03166001600160a01b031663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b1580156131d057600080fd5b505afa1580156131e4573d6000803e3d6000fd5b505050506040513d60208110156131fa57600080fd5b5051600e546001600160a01b0382161580159450919250906132da5780156132d5576000806132276133e1565b60085491935091506000906301000000900460ff166132525761324d6119778989612c35565b61325f565b61325f6119778484612ce8565b9050600061326c856132ee565b9050808211156132d05760006132936004610cf261328a8686612c98565b60025490612c35565b905060006132ac6132a5846004612c35565b8590613a2b565b905060008183816132b957fe5b04905080156132cc576132cc8982613340565b5050505b505050505b6132e6565b80156132e6576000600e555b505092915050565b60006003821115613331575080600160028204015b8181101561332b5780915060028182858161331a57fe5b04018161332357fe5b049050613303565b5061333b565b811561333b575060015b919050565b60025461334d9082613a2b565b6002556001600160a01b0382166000908152600360205260409020546133739082613a2b565b6001600160a01b03831660008181526003602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b60008183106133da5781611350565b5090919050565b6000806133ec61205c565b600f805463ffffffff808416600160a01b0263ffffffff60a01b19918616600160801b0263ffffffff60801b19909316929092171617905590939092509050565b600061135083836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613a7a565b6001600160a01b0382166000908152600360205260409020546134929082612c98565b6001600160a01b0383166000908152600360205260409020556002546134b89082612c98565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b600f5463ffffffff600160401b8204811692600160601b830482169282811692600160201b8204811692600160801b8304821692600160a01b900490911690565b60105460009063ffffffff80861690851611156135a35761359b61358b6135688584612c98565b612d5d6135754286612c98565b610cf263ffffffff8a811690808d1690612c9816565b63ffffffff8088169190613a2b16565b915050611350565b61359b6135d66135b38584612c98565b612d5d6135c04286612c98565b610cf263ffffffff8b811690808c1690612c9816565b63ffffffff8088169190612c9816565b6000826001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561362157600080fd5b505afa158015613635573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561365e57600080fd5b8101908080516040519392919084600160201b82111561367d57600080fd5b90830190602082018581111561369257600080fd5b8251600160201b8111828201881017156136ab57600080fd5b82525081516020918201929091019080838360005b838110156136d85781810151838201526020016136c0565b50505050905090810190601f1680156137055780820380516001836020036101000a031916815260200191505b50604052505050826001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561374557600080fd5b505afa158015613759573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561378257600080fd5b8101908080516040519392919084600160201b8211156137a157600080fd5b9083019060208201858111156137b657600080fd5b8251600160201b8111828201881017156137cf57600080fd5b82525081516020918201929091019080838360005b838110156137fc5781810151838201526020016137e4565b50505050905090810190601f1680156138295780820380516001836020036101000a031916815260200191505b506040525050506040516020018083805190602001908083835b602083106138625780518252601f199092019160209182019101613843565b6001836020036101000a03801982511681845116808217855250505050505090500180602f60f81b81525060010182805190602001908083835b602083106138bb5780518252601f19909201916020918201910161389c565b6001836020036101000a03801982511681845116808217855250505050505090500192505050604051602081830303815290604052905080604051602001808074024b6b837b9b9b4b136329029bbb0b8102628399d1605d1b81525060150182805190602001908083835b602083106139455780518252601f199092019160209182019101613926565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526000908051906020019061398e929190613c22565b5080604051602001808066024a316a6281d160cd1b81525060070182805190602001908083835b602083106139d45780518252601f1990920191602091820191016139b5565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405260019080519060200190613a1d929190613c22565b50613a26613b1c565b505050565b80820182811015610ef7576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b604482015290519081900360640190fd5b60008183613b065760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613acb578181015183820152602001613ab3565b50505050905090810190601f168015613af85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581613b1257fe5b0495945050505050565b60004690507f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040518082805460018160011615610100020316600290048015613b9f5780601f10613b7d576101008083540402835291820191613b9f565b820191906000526020600020905b815481529060010190602001808311613b8b575b505060408051918290038220828201825260018352603160f81b602093840152815180840196909652858201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606086015260808501959095523060a0808601919091528551808603909101815260c090940190945250508051910120600555565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282613c585760008555613c9e565b82601f10613c7157805160ff1916838001178555613c9e565b82800160010185558215613c9e579182015b82811115613c9e578251825591602001919060010190613c83565b50613caa929150613cae565b5090565b5b80821115613caa5760008155600101613caf56fe5265656e7472616e637947756172643a207265656e7472616e742063616c6c0049463a20494e53554646494349454e545f4c49515549444954595f4d494e54454449463a20494e53554646494349454e545f4c49515549444954595f4255524e4544a26469706673582212204dbf543a2bd3ad0712169d0b39f3521aca3ee7132f62965d35c4ab3664c5ec2164736f6c63430007060033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102485760003560e01c80637464fc3d1161013b578063c45a0155116100b8578063dd62ed3e1161007c578063dd62ed3e146106c4578063e94e3d8d146106f2578063f887ea401461072f578063f8c8765e14610737578063fff6cae91461077557610248565b8063c45a015514610626578063d1b2664f1461062e578063d21220a71461064b578063d4f0a77714610653578063d505accf1461067357610248565b8063a9059cbb116100ff578063a9059cbb14610599578063b6b9f61b146105c5578063ba9a7a56146105cd578063bb3a19a4146105d5578063bc25cf771461060057610248565b80637464fc3d1461053557806378e979251461053d5780637ecebe001461054557806389afcb441461056b57806395d89b411461059157610248565b8063313ce567116101c95780635de879701161018d5780635de87970146104bc57806364d62353146104c45780636a42b8f8146104e15780636a627842146104e957806370a082311461050f57610248565b8063313ce5671461047e5780633197cbb61461049c57806334762d09146104a45780633644e515146104ac578063590c61f0146104b457610248565b8063112db51b11610210578063112db51b146103db57806315fc3d92146103fb57806318160ddd1461042657806323b872dd1461044057806330adf81f1461047657610248565b8063022c0d9f1461024d57806306fdde03146102d95780630902f1ac14610356578063095ea7b3146103775780630dfe1681146103b7575b600080fd5b6102d76004803603608081101561026357600080fd5b8135916020810135916001600160a01b036040830135169190810190608081016060820135600160201b81111561029957600080fd5b8201836020820111156102ab57600080fd5b803590602001918460018302840111600160201b831117156102cc57600080fd5b50909250905061077d565b005b6102e1610e3d565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561031b578181015183820152602001610303565b50505050905090810190601f1680156103485780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61035e610ecb565b6040805192835260208301919091528051918290030190f35b6103a36004803603604081101561038d57600080fd5b506001600160a01b038135169060200135610ee6565b604080519115158252519081900360200190f35b6103bf610efd565b604080516001600160a01b039092168252519081900360200190f35b6102d7600480360360208110156103f157600080fd5b503560ff16610f0c565b6102d76004803603604081101561041157600080fd5b5063ffffffff813581169160200135166110de565b61042e6112bc565b60408051918252519081900360200190f35b6103a36004803603606081101561045657600080fd5b506001600160a01b038135811691602081013590911690604001356112c2565b61042e611357565b61048661137b565b6040805160ff9092168252519081900360200190f35b61042e611380565b6102d7611386565b61042e611650565b6103bf611656565b61042e611665565b6102d7600480360360208110156104da57600080fd5b503561166b565b61042e6117d5565b61042e600480360360208110156104ff57600080fd5b50356001600160a01b03166117db565b61042e6004803603602081101561052557600080fd5b50356001600160a01b0316611ac8565b61042e611ada565b61042e611ae0565b61042e6004803603602081101561055b57600080fd5b50356001600160a01b0316611ae6565b61035e6004803603602081101561058157600080fd5b50356001600160a01b0316611af8565b6102e1611ff5565b6103a3600480360360408110156105af57600080fd5b506001600160a01b03813516906020013561204f565b61035e61205c565b61042e6120fa565b6102d7600480360360408110156105eb57600080fd5b5063ffffffff81358116916020013516612100565b6102d76004803603602081101561061657600080fd5b50356001600160a01b0316612279565b6103bf6123d5565b6102d76004803603602081101561064457600080fd5b50356123eb565b6103bf612540565b6102d76004803603602081101561066957600080fd5b503560ff1661254f565b6102d7600480360360e081101561068957600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c0013561266d565b61042e600480360360408110156106da57600080fd5b506001600160a01b0381358116916020013516612860565b6106fa61287d565b604051808461ffff16815260200183600381111561071457fe5b81526020018215158152602001935050505060405180910390f35b6103bf61289c565b6102d76004803603608081101561074d57600080fd5b506001600160a01b0381358116916020810135821691604082013581169160600135166128ab565b6102d761295b565b600b546001600160a01b03163314806107a05750600c546001600160a01b031633145b6107e1576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b60026007541415610827576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b60026007558415158061083a5750600084115b61088b576040805162461bcd60e51b815260206004820152601e60248201527f49463a20494e53554646494349454e545f4f55545055545f414d4f554e540000604482015290519081900360640190fd5b600080610896610ecb565b915091508187111580156108aa5750808611155b6108fb576040805162461bcd60e51b815260206004820152601a60248201527f49463a20494e53554646494349454e545f4c4951554944495459000000000000604482015290519081900360640190fd5b6009546000908190819081906001600160a01b038a81169116148015906109305750600a546001600160a01b038a8116911614155b610972576040805162461bcd60e51b815260206004820152600e60248201526d49463a20494e56414c49445f544f60901b604482015290519081900360640190fd5b8a1561098f5760095461098f906001600160a01b03168a8d612aa6565b89156109ac57600a546109ac906001600160a01b03168a8c612aa6565b8615610a5e57886001600160a01b03166367e95e6f338d8d8c8c6040518663ffffffff1660e01b815260040180866001600160a01b03168152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b158015610a4557600080fd5b505af1158015610a59573d6000803e3d6000fd5b505050505b600954604080516370a0823160e01b815230600482015290516001600160a01b03909216916370a0823191602480820192602092909190829003018186803b158015610aa957600080fd5b505afa158015610abd573d6000803e3d6000fd5b505050506040513d6020811015610ad357600080fd5b5051600a54604080516370a0823160e01b815230600482015290519296506001600160a01b03909116916370a0823191602480820192602092909190829003018186803b158015610b2357600080fd5b505afa158015610b37573d6000803e3d6000fd5b505050506040513d6020811015610b4d57600080fd5b505192508a86038411610b61576000610b67565b8a860384035b91508985038311610b79576000610b7f565b89850383035b90506000821180610b905750600081115b610be1576040805162461bcd60e51b815260206004820152601d60248201527f49463a20494e53554646494349454e545f494e5055545f414d4f554e54000000604482015290519081900360640190fd5b60085460ff63010000008204169061ffff166000610c14610c028684612c35565b610c0e89612710612c35565b90612c98565b90506000610c25610c028685612c35565b90508315610d615760085462010000900460ff166000816003811115610c4757fe5b1480610c6757506001816003811115610c5c57fe5b148015610c6757508e155b80610c8657506002816003811115610c7b57fe5b148015610c8657508f155b610ccf576040805162461bcd60e51b815260206004820152601560248201527412518e88151490511157d393d517d0531313d5d151605a1b604482015290519081900360640190fd5b600080610cda61205c565b915091506000610cf86305f5e100610cf28585612ce8565b90612c35565b9050610d078383888885612d91565b610d58576040805162461bcd60e51b815260206004820152601760248201527f49463a20494e53554646494349454e545f5859424b5f4b000000000000000000604482015290519081900360640190fd5b50505050610dc9565b610d736305f5e100610cf28c8c612c35565b610d7d8383612c35565b1015610dc9576040805162461bcd60e51b815260206004820152601660248201527549463a20494e53554646494349454e545f554e495f4b60501b604482015290519081900360640190fd5b50505050610dd78484612e0b565b60408051838152602081018390528082018d9052606081018c905290516001600160a01b038b169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229181900360800190a350506001600755505050505050505050565b6000805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ec35780601f10610e9857610100808354040283529160200191610ec3565b820191906000526020600020905b815481529060010190602001808311610ea657829003601f168201915b505050505081565b600d546001600160801b0380821692600160801b9092041690565b6000610ef3338484612e8b565b5060015b92915050565b6009546001600160a01b031681565b600860049054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b158015610f5a57600080fd5b505afa158015610f6e573d6000803e3d6000fd5b505050506040513d6020811015610f8457600080fd5b50516001600160a01b03163314610fd2576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b60026007541415611018576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b60026007556008546301000000900460ff16611072576040805162461bcd60e51b815260206004820152601460248201527349463a2049535f43555252454e544c595f554e4960601b604482015290519081900360640190fd5b6008805482919062ff000019166201000083600381111561108f57fe5b02179055507f804ede6198c4ba5ac5c2ab3c86f51a6418ba3592262bf932bc9cbe6a18e4c79981604051808260038111156110c657fe5b815260200191505060405180910390a1506001600755565b600860049054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b15801561112c57600080fd5b505afa158015611140573d6000803e3d6000fd5b505050506040513d602081101561115657600080fd5b50516001600160a01b031633146111a4576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b600260075414156111ea576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b60026007556008546301000000900460ff1615611244576040805162461bcd60e51b815260206004820152601360248201527249463a2049535f414c52454144595f5859424b60681b604482015290519081900360640190fd5b61124e8282612eed565b6008805463ff0000001916630100000090811791829055604080519190920460ff161515815263ffffffff808516602083015283168183015290517fe81694441e8badb2a6bd046b401e64e8775f8055523d0263c9948f4a5b8026b39181900360600190a150506001600755565b60025481565b6001600160a01b038316600090815260046020908152604080832033845290915281205460001914611341576001600160a01b038416600090815260046020908152604080832033845290915290205461131c9083612c98565b6001600160a01b03851660009081526004602090815260408083203384529091529020555b61134c8484846130d1565b5060015b9392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b60115481565b600860049054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b1580156113d457600080fd5b505afa1580156113e8573d6000803e3d6000fd5b505050506040513d60208110156113fe57600080fd5b50516001600160a01b0316331461144c576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b60026007541415611492576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b60026007556008546301000000900460ff166114ea576040805162461bcd60e51b815260206004820152601260248201527149463a2049535f414c52454144595f554e4960701b604482015290519081900360640190fd5b601154421015611541576040805162461bcd60e51b815260206004820152601a60248201527f49463a20424f4f53545f414c52454144595f4348414e47494e47000000000000604482015290519081900360640190fd5b600f54600160401b900463ffffffff16600114801561156f5750600f54600160601b900463ffffffff166001145b6115b4576040805162461bcd60e51b815260206004820152601160248201527012518e881253959053125117d093d3d4d5607a1b604482015290519081900360640190fd5b6008805463ff000000191690819055600f805467ffffffff000000001963ffffffff1990911660011716600160201b179081905560408051630100000090930460ff1615158352600160401b820463ffffffff9081166020850152600160601b90920490911682820152517fe81694441e8badb2a6bd046b401e64e8775f8055523d0263c9948f4a5b8026b39181900360600190a16001600755565b60055481565b600c546001600160a01b031681565b60125481565b600860049054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b1580156116b957600080fd5b505afa1580156116cd573d6000803e3d6000fd5b505050506040513d60208110156116e357600080fd5b50516001600160a01b03163314611731576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b6201a5e0811015801561174957506013546212750010155b61178e576040805162461bcd60e51b815260206004820152601160248201527049463a20494e56414c49445f44454c415960781b604482015290519081900360640190fd5b6013805490829055604080518281526020810184905281517f40abb331f787260ef2fdd0c9e0ecc9bf68758a43190094281842f10ffcc318b2929181900390910190a15050565b60135481565b600060026007541415611823576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b6002600755600080611833610ecb565b600954604080516370a0823160e01b815230600482015290519395509193506000926001600160a01b03909116916370a08231916024808301926020929190829003018186803b15801561188657600080fd5b505afa15801561189a573d6000803e3d6000fd5b505050506040513d60208110156118b057600080fd5b5051600a54604080516370a0823160e01b815230600482015290519293506000926001600160a01b03909216916370a0823191602480820192602092909190829003018186803b15801561190357600080fd5b505afa158015611917573d6000803e3d6000fd5b505050506040513d602081101561192d57600080fd5b50519050600061193d8386612c98565b9050600061194b8386612c98565b90506000611959878761317f565b600254909150806119905761197c6103e8610c0e6119778787612c35565b6132ee565b985061198b60006103e8613340565b6119e3565b6119e0600089116119a3576000196119b7565b886119ae8684612c35565b816119b557fe5b045b600089116119c7576000196119db565b886119d28685612c35565b816119d957fe5b045b6133cb565b98505b60008911611a225760405162461bcd60e51b8152600401808060200182810382526021815260200180613ce46021913960400191505060405180910390fd5b611a2c8a8a613340565b611a368686612e0b565b600080611a416133e1565b915091508315611a79576008546301000000900460ff16611a6b57611a668888612c35565b611a75565b611a758282612ce8565b600e555b6040805187815260208101879052815133927f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f928290030190a250506001600755509698975050505050505050565b60036020526000908152604090205481565b600e5481565b60105481565b60066020526000908152604090205481565b60008060026007541415611b41576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b6002600755600080611b51610ecb565b915091506000611b61838361317f565b600954600a54604080516370a0823160e01b815230600482015290519394506001600160a01b0392831693919092169160009184916370a08231916024808301926020929190829003018186803b158015611bbb57600080fd5b505afa158015611bcf573d6000803e3d6000fd5b505050506040513d6020811015611be557600080fd5b5051604080516370a0823160e01b815230600482015290519192506000916001600160a01b038516916370a08231916024808301926020929190829003018186803b158015611c3357600080fd5b505afa158015611c47573d6000803e3d6000fd5b505050506040513d6020811015611c5d57600080fd5b5051306000908152600360205260409020546002549192509080611c818386612c35565b81611c8857fe5b049a5080611c968385612c35565b81611c9d57fe5b04995060008b1180611caf575060008a115b611cea5760405162461bcd60e51b8152600401808060200182810382526021815260200180613d056021913960400191505060405180910390fd5b6000600860049054906101000a90046001600160a01b03166001600160a01b031663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b158015611d3a57600080fd5b505afa158015611d4e573d6000803e3d6000fd5b505050506040513d6020811015611d6457600080fd5b50519050878015611d7e5750326001600160a01b03821614155b15611e4e57601254611d908d8261342d565b909c039b611d9e8c8261342d565b909b039a6000611dae858361342d565b9050611e3430600860049054906101000a90046001600160a01b03166001600160a01b031663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b158015611e0257600080fd5b505afa158015611e16573d6000803e3d6000fd5b505050506040513d6020811015611e2c57600080fd5b505183612aa6565b611e4730611e428784612c98565b61346f565b5050611e58565b611e58308461346f565b611e63878e8e612aa6565b611e6e868e8d612aa6565b5050604080516370a0823160e01b815230600482015290516001600160a01b038716916370a08231916024808301926020929190829003018186803b158015611eb657600080fd5b505afa158015611eca573d6000803e3d6000fd5b505050506040513d6020811015611ee057600080fd5b5051604080516370a0823160e01b815230600482015290519194506001600160a01b038616916370a0823191602480820192602092909190829003018186803b158015611f2c57600080fd5b505afa158015611f40573d6000803e3d6000fd5b505050506040513d6020811015611f5657600080fd5b50519150611f648383612e0b565b8515611f98576008546301000000900460ff16611f8a57611f858383612c35565b611f94565b611f948383612ce8565b600e555b604080518b8152602081018b905281516001600160a01b038e169233927fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496929081900390910190a350505050505050506001600781905550915091565b60018054604080516020600284861615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ec35780601f10610e9857610100808354040283529160200191610ec3565b6000610ef33384846130d1565b6000806000601154905080421061209157600080612078613500565b505063ffffffff938416985050501693506120f5915050565b6000806000806000806120a2613500565b9550955095509550955095506120b9848789613541565b98506120c6838689613541565b9750600e546120d58a8a612ce8565b10156120ee578163ffffffff1698508063ffffffff1697505b5050505050505b509091565b6103e881565b600860049054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b15801561214e57600080fd5b505afa158015612162573d6000803e3d6000fd5b505050506040513d602081101561217857600080fd5b50516001600160a01b031633146121c6576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b6002600754141561220c576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b60026007556008546301000000900460ff16612266576040805162461bcd60e51b815260206004820152601460248201527349463a2049535f43555252454e544c595f554e4960601b604482015290519081900360640190fd5b6122708282612eed565b50506001600755565b600260075414156122bf576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b6002600755600954600a546001600160a01b0391821691166000806122e2610ecb565b91509150612373848661236e85886001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561233c57600080fd5b505afa158015612350573d6000803e3d6000fd5b505050506040513d602081101561236657600080fd5b505190612c98565b612aa6565b6123c9838661236e84876001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561233c57600080fd5b50506001600755505050565b600854600160201b90046001600160a01b031681565b600860049054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b15801561243957600080fd5b505afa15801561244d573d6000803e3d6000fd5b505050506040513d602081101561246357600080fd5b50516001600160a01b031633146124b1576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b60648110156124f9576040805162461bcd60e51b815260206004820152600f60248201526e49463a20494e56414c49445f46454560881b604482015290519081900360640190fd5b6012805490829055604080518281526020810184905281517f985b27d3fed0c26bf4c91858b7a7bf9f3406337d65fcb519d177f56758627508929181900390910190a15050565b600a546001600160a01b031681565b600860049054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b15801561259d57600080fd5b505afa1580156125b1573d6000803e3d6000fd5b505050506040513d60208110156125c757600080fd5b50516001600160a01b03163314612615576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b6008805460ff831661ffff19821681179092556040805161ffff909216808352602083019390935280517f907af1ce671677e36d7827744cdc6febfa3a1124adfb2bfb5288e1ae9896dda29281900390910190a15050565b428410156126b0576040805162461bcd60e51b815260206004820152600b60248201526a12518e881156141254915160aa1b604482015290519081900360640190fd5b6005546001600160a01b0380891660008181526006602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e08501825280519083012061190160f01b6101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e280820193601f1981019281900390910190855afa1580156127cb573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906128015750886001600160a01b0316816001600160a01b0316145b61284a576040805162461bcd60e51b815260206004820152601560248201527449463a20494e56414c49445f5349474e415455524560581b604482015290519081900360640190fd5b612855898989612e8b565b505050505050505050565b600460209081526000928352604080842090915290825290205481565b60085461ffff81169160ff620100008304811692630100000090041690565b600b546001600160a01b031681565b600854600160201b90046001600160a01b03163314612901576040805162461bcd60e51b815260206004820152600d60248201526c24a31d102327a92124a22222a760991b604482015290519081900360640190fd5b600b80546001600160a01b038085166001600160a01b031992831617909255600c805484841690831617905560098054878416908316179055600a80549286169290911691909117905561295584846135e6565b50505050565b600260075414156129a1576040805162461bcd60e51b815260206004820152601f6024820152600080516020613cc4833981519152604482015290519081900360640190fd5b6002600755600954604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b1580156129f157600080fd5b505afa158015612a05573d6000803e3d6000fd5b505050506040513d6020811015612a1b57600080fd5b5051600a54604080516370a0823160e01b815230600482015290519293506000926001600160a01b03909216916370a0823191602480820192602092909190829003018186803b158015612a6e57600080fd5b505afa158015612a82573d6000803e3d6000fd5b505050506040513d6020811015612a9857600080fd5b505190506122708282612e0b565b604080518082018252601981527f7472616e7366657228616464726573732c75696e74323536290000000000000060209182015281516001600160a01b0385811660248301526044808301869052845180840390910181526064909201845291810180516001600160e01b031663a9059cbb60e01b17815292518151600094859489169392918291908083835b60208310612b525780518252601f199092019160209182019101612b33565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612bb4576040519150601f19603f3d011682016040523d82523d6000602084013e612bb9565b606091505b5091509150818015612be7575080511580612be75750808060200190516020811015612be457600080fd5b50515b612c2e576040805162461bcd60e51b815260206004820152601360248201527212518e881514905394d1915497d19052531151606a1b604482015290519081900360640190fd5b5050505050565b6000811580612c5057505080820282828281612c4d57fe5b04145b610ef7576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604482015290519081900360640190fd5b80820382811115610ef7576040805162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b604482015290519081900360640190fd5b6000806000612cf5610ecb565b915091506000818311612d1257612d0d856001612c98565b612d1d565b612d1d866001612c98565b90506000612d376001612d31846002612c35565b90613a2b565b90506000612d63612d49836002612c35565b612d5d612d568888613a2b565b8690612c35565b9061342d565b9050600281612d83612d7985612d5d8a8a612c35565b6002850a016132ee565b010a98975050505050505050565b600080612d9d836132ee565b90506000848611612db857612db3876001612c98565b612dc3565b612dc3886001612c98565b90506000612dd18284612c35565b905084612dfc6002612de4856001613a2b565b0a612d5d612df28a86613a2b565b610cf28c87613a2b565b10159998505050505050505050565b600d80546fffffffffffffffffffffffffffffffff19166001600160801b03848116919091178116600160801b8483168102919091179283905560408051848416815291909304909116602082015281517fcf2aa50876cdfbb541206f89af0ee78d44a2abf8d328e37fa4917f982149848a929181900390910190a15050565b6001600160a01b03808416600081815260046020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b60018263ffffffff1610158015612f0b575060018163ffffffff1610155b8015612f205750620f42408263ffffffff1611155b8015612f355750620f42408163ffffffff1611155b612f7a576040805162461bcd60e51b815260206004820152601160248201527012518e881253959053125117d093d3d4d5607a1b604482015290519081900360640190fd5b6011544290811015612fd3576040805162461bcd60e51b815260206004820152601a60248201527f49463a20424f4f53545f414c52454144595f4348414e47494e47000000000000604482015290519081900360640190fd5b600080612fde610ecb565b91509150612fec828261317f565b50600f805467ffffffff0000000019600160401b80830463ffffffff90811663ffffffff1990941693909317918216600160601b928390048416600160201b908102919091176bffffffff000000000000000019168a851683021763ffffffff60601b191689851684021794859055601088905560135488016011819055604080518787168152928704861660208401529286048516828401529290940490921660608401526080830186905260a0830152517ff771495302afb2f84f43cab3d699e9548748b5154c0c8feba486d0e3e1d860799160c0908290030190a15050505050565b6001600160a01b0383166000908152600360205260409020546130f49082612c98565b6001600160a01b0380851660009081526003602052604080822093909355908416815220546131239082613a2b565b6001600160a01b0380841660008181526003602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600080600860049054906101000a90046001600160a01b03166001600160a01b031663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b1580156131d057600080fd5b505afa1580156131e4573d6000803e3d6000fd5b505050506040513d60208110156131fa57600080fd5b5051600e546001600160a01b0382161580159450919250906132da5780156132d5576000806132276133e1565b60085491935091506000906301000000900460ff166132525761324d6119778989612c35565b61325f565b61325f6119778484612ce8565b9050600061326c856132ee565b9050808211156132d05760006132936004610cf261328a8686612c98565b60025490612c35565b905060006132ac6132a5846004612c35565b8590613a2b565b905060008183816132b957fe5b04905080156132cc576132cc8982613340565b5050505b505050505b6132e6565b80156132e6576000600e555b505092915050565b60006003821115613331575080600160028204015b8181101561332b5780915060028182858161331a57fe5b04018161332357fe5b049050613303565b5061333b565b811561333b575060015b919050565b60025461334d9082613a2b565b6002556001600160a01b0382166000908152600360205260409020546133739082613a2b565b6001600160a01b03831660008181526003602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b60008183106133da5781611350565b5090919050565b6000806133ec61205c565b600f805463ffffffff808416600160a01b0263ffffffff60a01b19918616600160801b0263ffffffff60801b19909316929092171617905590939092509050565b600061135083836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613a7a565b6001600160a01b0382166000908152600360205260409020546134929082612c98565b6001600160a01b0383166000908152600360205260409020556002546134b89082612c98565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b600f5463ffffffff600160401b8204811692600160601b830482169282811692600160201b8204811692600160801b8304821692600160a01b900490911690565b60105460009063ffffffff80861690851611156135a35761359b61358b6135688584612c98565b612d5d6135754286612c98565b610cf263ffffffff8a811690808d1690612c9816565b63ffffffff8088169190613a2b16565b915050611350565b61359b6135d66135b38584612c98565b612d5d6135c04286612c98565b610cf263ffffffff8b811690808c1690612c9816565b63ffffffff8088169190612c9816565b6000826001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561362157600080fd5b505afa158015613635573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561365e57600080fd5b8101908080516040519392919084600160201b82111561367d57600080fd5b90830190602082018581111561369257600080fd5b8251600160201b8111828201881017156136ab57600080fd5b82525081516020918201929091019080838360005b838110156136d85781810151838201526020016136c0565b50505050905090810190601f1680156137055780820380516001836020036101000a031916815260200191505b50604052505050826001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561374557600080fd5b505afa158015613759573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561378257600080fd5b8101908080516040519392919084600160201b8211156137a157600080fd5b9083019060208201858111156137b657600080fd5b8251600160201b8111828201881017156137cf57600080fd5b82525081516020918201929091019080838360005b838110156137fc5781810151838201526020016137e4565b50505050905090810190601f1680156138295780820380516001836020036101000a031916815260200191505b506040525050506040516020018083805190602001908083835b602083106138625780518252601f199092019160209182019101613843565b6001836020036101000a03801982511681845116808217855250505050505090500180602f60f81b81525060010182805190602001908083835b602083106138bb5780518252601f19909201916020918201910161389c565b6001836020036101000a03801982511681845116808217855250505050505090500192505050604051602081830303815290604052905080604051602001808074024b6b837b9b9b4b136329029bbb0b8102628399d1605d1b81525060150182805190602001908083835b602083106139455780518252601f199092019160209182019101613926565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526000908051906020019061398e929190613c22565b5080604051602001808066024a316a6281d160cd1b81525060070182805190602001908083835b602083106139d45780518252601f1990920191602091820191016139b5565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405260019080519060200190613a1d929190613c22565b50613a26613b1c565b505050565b80820182811015610ef7576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b604482015290519081900360640190fd5b60008183613b065760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613acb578181015183820152602001613ab3565b50505050905090810190601f168015613af85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581613b1257fe5b0495945050505050565b60004690507f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040518082805460018160011615610100020316600290048015613b9f5780601f10613b7d576101008083540402835291820191613b9f565b820191906000526020600020905b815481529060010190602001808311613b8b575b505060408051918290038220828201825260018352603160f81b602093840152815180840196909652858201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606086015260808501959095523060a0808601919091528551808603909101815260c090940190945250508051910120600555565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282613c585760008555613c9e565b82601f10613c7157805160ff1916838001178555613c9e565b82800160010185558215613c9e579182015b82811115613c9e578251825591602001919060010190613c83565b50613caa929150613cae565b5090565b5b80821115613caa5760008155600101613caf56fe5265656e7472616e637947756172643a207265656e7472616e742063616c6c0049463a20494e53554646494349454e545f4c49515549444954595f4d494e54454449463a20494e53554646494349454e545f4c49515549444954595f4255524e4544a26469706673582212204dbf543a2bd3ad0712169d0b39f3521aca3ee7132f62965d35c4ab3664c5ec2164736f6c63430007060033

Deployed Bytecode Sourcemap

715:25006:1:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20108:2929;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;20108:2929:1;;;;;;;;;;;;;-1:-1:-1;;;20108:2929:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;20108:2929:1;;;;;;;;;;-1:-1:-1;20108:2929:1;;-1:-1:-1;20108:2929:1;-1:-1:-1;20108:2929:1;:::i;:::-;;258:51:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4011:176:1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;2853:156:0;;;;;;;;;;;;;;;;-1:-1:-1;2853:156:0;;-1:-1:-1;;;;;2853:156:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;1510:30:1;;;:::i;:::-;;;;-1:-1:-1;;;;;1510:30:1;;;;;;;;;;;;;;10372:222;;;;;;;;;;;;;;;;-1:-1:-1;10372:222:1;;;;:::i;8248:280::-;;;;;;;;;;;;;;;;-1:-1:-1;8248:280:1;;;;;;;;;;;:::i;410:35:0:-;;;:::i;:::-;;;;;;;;;;;;;;;;3169:340;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;3169:340:0;;;;;;;;;;;;;;;;;:::i;740:125::-;;;:::i;360:44::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;2579:22:1;;;:::i;8722:447::-;;;:::i;590:40:0:-;;;:::i;1609:30:1:-;;;:::i;2719:39::-;;;:::i;9913:268::-;;;;;;;;;;;;;;;;-1:-1:-1;9913:268:1;;:::i;2909:39::-;;;:::i;15788:1332::-;;;;;;;;;;;;;;;;-1:-1:-1;15788:1332:1;-1:-1:-1;;;;;15788:1332:1;;:::i;451:53:0:-;;;;;;;;;;;;;;;;-1:-1:-1;451:53:0;-1:-1:-1;;;;;451:53:0;;:::i;1707:20:1:-;;;:::i;2549:24::-;;;:::i;871:50:0:-;;;;;;;;;;;;;;;;-1:-1:-1;871:50:0;-1:-1:-1;;;;;871:50:0;;:::i;17533:2041:1:-;;;;;;;;;;;;;;;;-1:-1:-1;17533:2041:1;-1:-1:-1;;;;;17533:2041:1;;:::i;315:39:0:-;;;:::i;3015:148::-;;;;;;;;;;;;;;;;-1:-1:-1;3015:148:0;;-1:-1:-1;;;;;3015:148:0;;;;;;:::i;6266:904:1:-;;;:::i;831:58::-;;;:::i;10849:198::-;;;;;;;;;;;;;;;;-1:-1:-1;10849:198:1;;;;;;;;;;;:::i;25008:412::-;;;;;;;;;;;;;;;;-1:-1:-1;25008:412:1;-1:-1:-1;;;;;25008:412:1;;:::i;1473:31::-;;;:::i;12328:322::-;;;;;;;;;;;;;;;;-1:-1:-1;12328:322:1;;:::i;1546:30::-;;;:::i;9486:191::-;;;;;;;;;;;;;;;;-1:-1:-1;9486:191:1;;;;:::i;3515:725:0:-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;3515:725:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3515:725:0;;;;;;;;:::i;510:73::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;510:73:0;;;;;;;;;;:::i;3524:294:1:-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1582:21;;;:::i;13223:382::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;13223:382:1;;;;;;;;;;;;;;;;;;;;;;;;:::i;25488:231::-;;;:::i;20108:2929::-;3011:6;;-1:-1:-1;;;;;3011:6:1;2997:10;:20;;:53;;-1:-1:-1;3035:15:1;;-1:-1:-1;;;;;3035:15:1;3021:10;:29;2997:53;2989:79;;;;;-1:-1:-1;;;2989:79:1;;;;;;;;;;;;-1:-1:-1;;;2989:79:1;;;;;;;;;;;;;;;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;20295:14:1;;;;:32:::2;;;20326:1;20313:10;:14;20295:32;20287:75;;;::::0;;-1:-1:-1;;;20287:75:1;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;;;;;;;;;;;;::::2;;20373:17;20392::::0;20413:13:::2;:11;:13::i;:::-;20372:54;;;;20473:9;20459:10;:23;;:50;;;;;20500:9;20486:10;:23;;20459:50;20451:89;;;::::0;;-1:-1:-1;;;20451:89:1;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;;;;;;;;;;;;::::2;;20685:6;::::0;20551:16:::2;::::0;;;;;;;-1:-1:-1;;;;;20679:12:1;;::::2;20685:6:::0;::::2;20679:12;::::0;::::2;::::0;:28:::2;;-1:-1:-1::0;20701:6:1::2;::::0;-1:-1:-1;;;;;20695:12:1;;::::2;20701:6:::0;::::2;20695:12;;20679:28;20671:55;;;::::0;;-1:-1:-1;;;20671:55:1;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;-1:-1:-1;;;20671:55:1;;;;;;;;;;;;;::::2;;20744:14:::0;;20740:57:::2;;20774:6;::::0;20760:37:::2;::::0;-1:-1:-1;;;;;20774:6:1::2;20782:2:::0;20786:10;20760:13:::2;:37::i;:::-;20849:14:::0;;20845:57:::2;;20879:6;::::0;20865:37:::2;::::0;-1:-1:-1;;;;;20879:6:1::2;20887:2:::0;20891:10;20865:13:::2;:37::i;:::-;20954:15:::0;;20950:99:::2;;20989:2;-1:-1:-1::0;;;;;20971:36:1::2;;21008:10;21020;21032;21044:4;;20971:78;;;;;;;;;;;;;-1:-1:-1::0;;;;;20971:78:1::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;20950:99;21081:6;::::0;21074:39:::2;::::0;;-1:-1:-1;;;21074:39:1;;21107:4:::2;21074:39;::::0;::::2;::::0;;;-1:-1:-1;;;;;21081:6:1;;::::2;::::0;-1:-1:-1;;21074:39:1;;;;;::::2;::::0;;;;;;;;;21081:6;21074:39;::::2;;::::0;::::2;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;::::0;::::2;;-1:-1:-1::0;21074:39:1;21145:6:::2;::::0;21138:39:::2;::::0;;-1:-1:-1;;;21138:39:1;;21171:4:::2;21138:39;::::0;::::2;::::0;;;21074;;-1:-1:-1;;;;;;21145:6:1;;::::2;::::0;-1:-1:-1;;21138:39:1;;;;;21074::::2;::::0;21138;;;;;;;;21145:6;21138:39;::::2;;::::0;::::2;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;::::0;::::2;;-1:-1:-1::0;21138:39:1;;-1:-1:-1;21242:22:1;;::::2;21231:33:::0;::::2;:75;;21305:1;21231:75;;;21291:10;21279:9;:22;21267:8;:35;21231:75;21219:87;;21355:10;21343:9;:22;21332:8;:33;:75;;21406:1;21332:75;;;21392:10;21380:9;:22;21368:8;:35;21332:75;21320:87;;21448:1;21436:9;:13;:30;;;;21465:1;21453:9;:13;21436:30;21428:72;;;::::0;;-1:-1:-1;;;21428:72:1;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;;;;;;;;;;;;::::2;;21583:6;::::0;::::2;::::0;;::::2;;::::0;21631:8:::2;;21568:12;21681:49;21705:24;:9:::0;21631:8;21705:13:::2;:24::i;:::-;21681:19;:8:::0;21694:5:::2;21681:12;:19::i;:::-;:23:::0;::::2;:49::i;:::-;21654:76:::0;-1:-1:-1;21773:24:1::2;21800:49;21824:24;:9:::0;21838;21824:13:::2;:24::i;21800:49::-;21773:76;;21896:7;21892:1009;;;21991:10;::::0;;;::::2;;;21966:22;22049:11;:34;;;;;;;;;22048:123;;;-1:-1:-1::0;22128:23:1::2;22113:11;:38;;;;;;;;;:57;;;;-1:-1:-1::0;22155:15:1;;22113:57:::2;22048:210;;;-1:-1:-1::0;22215:23:1::2;22200:11;:38;;;;;;;;;:57;;;;-1:-1:-1::0;22242:15:1;;22200:57:::2;22019:302;;;::::0;;-1:-1:-1;;;22019:302:1;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;-1:-1:-1;;;22019:302:1;;;;;;;;;;;;;::::2;;22341:14;22357::::0;22375:11:::2;:9;:11::i;:::-;22340:46;;;;22425:18;22446:42;22479:8;22446:28;22459:6;22467;22446:12;:28::i;:::-;:32:::0;::::2;:42::i;:::-;22425:63;;22535:74;22546:6;22554;22562:16;22580;22598:10;22535;:74::i;:::-;22506:168;;;::::0;;-1:-1:-1;;;22506:168:1;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;;;;;;;;;;;;::::2;;21892:1009;;;;;;;22784:38;22813:8;22784:24;:9:::0;22798;22784:13:::2;:24::i;:38::-;22742;:16:::0;22763;22742:20:::2;:38::i;:::-;:80;;22713:173;;;::::0;;-1:-1:-1;;;22713:173:1;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;-1:-1:-1;;;22713:173:1;;;;;;;;;;;;;::::2;;2426:1:19;;;;22921:27:1;22929:8;22939;22921:7;:27::i;:::-;22964:66;::::0;;;;;::::2;::::0;::::2;::::0;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;22964:66:1;::::2;::::0;22969:10:::2;::::0;22964:66:::2;::::0;;;;;;;::::2;-1:-1:-1::0;;1645:1:19::1;2570:7;:22:::0;-1:-1:-1;;;;;;;;;20108:2929:1:o;258:51:0:-;;;;;;;;;;;;;;;-1:-1:-1;;258:51:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;4011:176:1:-;4132:8;;-1:-1:-1;;;;;4132:8:1;;;;-1:-1:-1;;;4171:8:1;;;;;4011:176::o;2853:156:0:-;2929:4;2945:36;2954:10;2966:7;2975:5;2945:8;:36::i;:::-;-1:-1:-1;2998:4:0;2853:156;;;;;:::o;1510:30:1:-;;;-1:-1:-1;;;;;1510:30:1;;:::o;10372:222::-;3173:7;;3150:44;;;-1:-1:-1;;;3150:44:1;;;;-1:-1:-1;;;3173:7:1;;;-1:-1:-1;;;;;3173:7:1;;3150:42;;3173:7;3150:44;;;;;;;;;;;;;;3173:7;3150:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3150:44:1;-1:-1:-1;;;;;3136:58:1;:10;:58;3128:84;;;;;-1:-1:-1;;;3128:84:1;;;;;;;;;;;;-1:-1:-1;;;3128:84:1;;;;;;;;;;;;;;;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;10477:6:1::2;::::0;;;::::2;;;10469:39;;;::::0;;-1:-1:-1;;;10469:39:1;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;-1:-1:-1;;;10469:39:1;;;;;;;;;;;;;::::2;;10518:10;:24:::0;;10531:11;;10518:10;-1:-1:-1;;10518:24:1::2;::::0;10531:11;10518:24:::2;::::0;::::2;;;;;;;;;;;10557:30;10575:11;10557:30;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;1645:1:19::1;2570:7;:22:::0;10372:222:1:o;8248:280::-;3173:7;;3150:44;;;-1:-1:-1;;;3150:44:1;;;;-1:-1:-1;;;3173:7:1;;;-1:-1:-1;;;;;3173:7:1;;3150:42;;3173:7;3150:44;;;;;;;;;;;;;;3173:7;3150:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3150:44:1;-1:-1:-1;;;;;3136:58:1;:10;:58;3128:84;;;;;-1:-1:-1;;;3128:84:1;;;;;;;;;;;;-1:-1:-1;;;3128:84:1;;;;;;;;;;;;;;;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;8360:6:1::2;::::0;;;::::2;;;8359:7;8351:39;;;::::0;;-1:-1:-1;;;8351:39:1;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;-1:-1:-1;;;8351:39:1;;;;;;;;;;;;;::::2;;8400:36;8413:10;8425;8400:12;:36::i;:::-;8446:6;:13:::0;;-1:-1:-1;;8446:13:1::2;::::0;;;::::2;::::0;;;;8474:47:::2;::::0;;8490:6;;;::::2;8446:13;8490:6;8474:47;;::::0;;::::2;::::0;;::::2;;::::0;::::2;::::0;;::::2;::::0;;;;;;::::2;::::0;;;;;;;::::2;-1:-1:-1::0;;1645:1:19::1;2570:7;:22:::0;8248:280:1:o;410:35:0:-;;;;:::o;3169:340::-;-1:-1:-1;;;;;3309:15:0;;3289:4;3309:15;;;:9;:15;;;;;;;;3325:10;3309:27;;;;;;;;-1:-1:-1;;3309:42:0;3305:141;;-1:-1:-1;;;;;3397:15:0;;;;;;:9;:15;;;;;;;;3413:10;3397:27;;;;;;;;:38;;3429:5;3397:31;:38::i;:::-;-1:-1:-1;;;;;3367:15:0;;;;;;:9;:15;;;;;;;;3383:10;3367:27;;;;;;;:68;3305:141;3455:26;3465:4;3471:2;3475:5;3455:9;:26::i;:::-;-1:-1:-1;3498:4:0;3169:340;;;;;;:::o;740:125::-;799:66;740:125;:::o;360:44::-;402:2;360:44;:::o;2579:22:1:-;;;;:::o;8722:447::-;3173:7;;3150:44;;;-1:-1:-1;;;3150:44:1;;;;-1:-1:-1;;;3173:7:1;;;-1:-1:-1;;;;;3173:7:1;;3150:42;;3173:7;3150:44;;;;;;;;;;;;;;3173:7;3150:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3150:44:1;-1:-1:-1;;;;;3136:58:1;:10;:58;3128:84;;;;;-1:-1:-1;;;3128:84:1;;;;;;;;;;;;-1:-1:-1;;;3128:84:1;;;;;;;;;;;;;;;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;8796:6:1::2;::::0;;;::::2;;;8788:37;;;::::0;;-1:-1:-1;;;8788:37:1;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;-1:-1:-1;;;8788:37:1;;;;;;;;;;;;;::::2;;8862:7;;8843:15;:26;;8835:65;;;::::0;;-1:-1:-1;;;8835:65:1;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;;;;;;;;;;;;::::2;;8918:9;::::0;::::2;-1:-1:-1::0;;;8918:9:1;;::::2;;-1:-1:-1::0;8918:14:1::2;:32:::0;::::2;;;-1:-1:-1::0;8936:9:1::2;::::0;::::2;-1:-1:-1::0;;;8936:9:1;;::::2;;-1:-1:-1::0;8936:14:1::2;8918:32;8910:62;;;::::0;;-1:-1:-1;;;8910:62:1;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;-1:-1:-1;;;8910:62:1;;;;;;;;;;;;;::::2;;8982:6;:14:::0;;-1:-1:-1;;8982:14:1::2;::::0;;;;9006:9:::2;:13:::0;;-1:-1:-1;;;;9006:13:1;;::::2;-1:-1:-1::0;9006:13:1::2;9047;-1:-1:-1::0;;;9047:13:1::2;::::0;;;;9117:45:::2;::::0;;8982:14;9133:6;;::::2;8982:14;9133:6;9117:45;;::::0;;-1:-1:-1;;;;9141:9:1;::::2;::::0;::::2;-1:-1:-1::0;9117:45:1;::::2;::::0;-1:-1:-1;;;9152:9:1;;::::2;::::0;;::::2;9117:45:::0;;;;;::::2;::::0;-1:-1:-1;9117:45:1;;;;;;::::2;1645:1:19::1;2570:7;:22:::0;8722:447:1:o;590:40:0:-;;;;:::o;1609:30:1:-;;;-1:-1:-1;;;;;1609:30:1;;:::o;2719:39::-;;;;:::o;9913:268::-;3173:7;;3150:44;;;-1:-1:-1;;;3150:44:1;;;;-1:-1:-1;;;3173:7:1;;;-1:-1:-1;;;;;3173:7:1;;3150:42;;3173:7;3150:44;;;;;;;;;;;;;;3173:7;3150:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3150:44:1;-1:-1:-1;;;;;3136:58:1;:10;:58;3128:84;;;;;-1:-1:-1;;;3128:84:1;;;;;;;;;;;;-1:-1:-1;;;3128:84:1;;;;;;;;;;;;;;;1084:6:::1;9995:9;:24;;:46;;;;-1:-1:-1::0;10023:5:1::1;::::0;1132:7:::1;-1:-1:-1::0;10023:18:1::1;9995:46;9987:76;;;::::0;;-1:-1:-1;;;9987:76:1;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;9987:76:1;;;;;;;;;;;;;::::1;;10093:5;::::0;;10108:17;;;;10140:34:::1;::::0;;;;;::::1;::::0;::::1;::::0;;;;;::::1;::::0;;;;;;;;;::::1;3222:1;9913:268:::0;:::o;2909:39::-;;;;:::o;15788:1332::-;15854:17;1688:1:19;2267:7;;:19;;2259:63;;;;;-1:-1:-1;;;2259:63:19;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;;;1688:1;2397:7;:18;15884:17:1::1;::::0;15924:13:::1;:11;:13::i;:::-;15988:6;::::0;15981:39:::1;::::0;;-1:-1:-1;;;15981:39:1;;16014:4:::1;15981:39;::::0;::::1;::::0;;;15883:54;;-1:-1:-1;15883:54:1;;-1:-1:-1;;;;;;;;15988:6:1;;::::1;::::0;-1:-1:-1;;15981:39:1;;;;;::::1;::::0;;;;;;;;15988:6;15981:39;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;15981:39:1;16056:6:::1;::::0;16049:39:::1;::::0;;-1:-1:-1;;;16049:39:1;;16082:4:::1;16049:39;::::0;::::1;::::0;;;15981;;-1:-1:-1;;;;;;;;16056:6:1;;::::1;::::0;-1:-1:-1;;16049:39:1;;;;;15981::::1;::::0;16049;;;;;;;;16056:6;16049:39;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;16049:39:1;;-1:-1:-1;16098:15:1::1;16116:23;:8:::0;16129:9;16116:12:::1;:23::i;:::-;16098:41:::0;-1:-1:-1;16149:15:1::1;16167:23;:8:::0;16180:9;16167:12:::1;:23::i;:::-;16149:41;;16201:10;16214:30;16223:9;16234;16214:8;:30::i;:::-;16277:11;::::0;16201:43;;-1:-1:-1;16317:17:1;16313:454:::1;;16362:54;884:5;16362:31;16372:20;:7:::0;16384;16372:11:::1;:20::i;:::-;16362:9;:31::i;:54::-;16350:66;;16430:36;16444:1;884:5;16430;:36::i;:::-;16313:454;;;16564:192;16602:1;16590:9;:13;:67;;-1:-1:-1::0;;16590:67:1::1;;;16634:9:::0;16606:25:::1;:7:::0;16618:12;16606:11:::1;:25::i;:::-;:37;;;;;;16590:67;16687:1;16675:9;:13;:67;;-1:-1:-1::0;;16675:67:1::1;;;16719:9:::0;16691:25:::1;:7:::0;16703:12;16691:11:::1;:25::i;:::-;:37;;;;;;16675:67;16564:8;:192::i;:::-;16552:204;;16313:454;16796:1;16784:9;:13;16776:59;;;;-1:-1:-1::0;;;16776:59:1::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;16845:20;16851:2;16855:9;16845:5;:20::i;:::-;16876:27;16884:8;16894;16876:7;:27::i;:::-;16914:15;16931::::0;16950:21:::1;:19;:21::i;:::-;16913:58;;;;16985:5;16981:83;;;17000:6;::::0;;;::::1;;;:64;;17042:22;:8:::0;17055;17042:12:::1;:22::i;:::-;17000:64;;;17009:30;17022:7;17031;17009:12;:30::i;:::-;16992:5;:72:::0;16981:83:::1;17079:34;::::0;;;;;::::1;::::0;::::1;::::0;;;;;17084:10:::1;::::0;17079:34:::1;::::0;;;;;;::::1;-1:-1:-1::0;;1645:1:19;2570:7;:22;-1:-1:-1;15788:1332:1;;;-1:-1:-1;;;;;;;;15788:1332:1:o;451:53:0:-;;;;;;;;;;;;;:::o;1707:20:1:-;;;;:::o;2549:24::-;;;;:::o;871:50:0:-;;;;;;;;;;;;;:::o;17533:2041:1:-;17599:15;17616;1688:1:19;2267:7;;:19;;2259:63;;;;;-1:-1:-1;;;2259:63:19;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;;;1688:1;2397:7;:18;17644:17:1::1;::::0;17684:13:::1;:11;:13::i;:::-;17643:54;;;;17722:10;17735:30;17744:9;17755;17735:8;:30::i;:::-;17793:6;::::0;17842::::1;::::0;17892:40:::1;::::0;;-1:-1:-1;;;17892:40:1;;17926:4:::1;17892:40;::::0;::::1;::::0;;;17722:43;;-1:-1:-1;;;;;;17793:6:1;;::::1;::::0;17842;;;::::1;::::0;-1:-1:-1;;17793:6:1;;-1:-1:-1;;17892:40:1;;;;;::::1;::::0;;;;;;;;;17793:6;17892:40;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;17892:40:1;17961::::1;::::0;;-1:-1:-1;;;17961:40:1;;17995:4:::1;17961:40;::::0;::::1;::::0;;;17892;;-1:-1:-1;;;;;;;;17961:25:1;::::1;::::0;-1:-1:-1;;17961:40:1;;;;;17892::::1;::::0;17961;;;;;;;:25;:40;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;17961:40:1;18049:4:::1;18011:17;18031:24:::0;;;:9:::1;17961:40;18031:24:::0;;;;;18103:11:::1;::::0;17961:40;;-1:-1:-1;18031:24:1;18103:11;18138:23:::1;18031:24:::0;18152:8;18138:13:::1;:23::i;:::-;:38;;;;;;::::0;-1:-1:-1;18226:12:1;18200:23:::1;:9:::0;18214:8;18200:13:::1;:23::i;:::-;:38;;;;;;18190:48;;18270:1;18260:7;:11;:26;;;;18285:1;18275:7;:11;18260:26;18252:72;;;;-1:-1:-1::0;;;18252:72:1::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18379:7;::::0;18356:39:::1;::::0;;-1:-1:-1;;;18356:39:1;;;;18339:14:::1;::::0;-1:-1:-1;;;18379:7:1;::::1;-1:-1:-1::0;;;;;18379:7:1::1;::::0;18356:37:::1;::::0;18379:7:::1;18356:39:::0;;::::1;::::0;::::1;::::0;;;;;;;;18379:7;18356:39;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;18356:39:1;;-1:-1:-1;18504:5:1;:28;::::1;;;-1:-1:-1::0;;;;;;18513:19:1;::::1;:9;:19;;18504:28;18500:615;;;18572:18;::::0;18650:22:::1;:7:::0;18572:18;18650:11:::1;:22::i;:::-;18639:33:::0;;::::1;::::0;18701:22:::1;:7:::0;18713:9;18701:11:::1;:22::i;:::-;18690:33:::0;;::::1;::::0;18809:22:::1;18834:24;:9:::0;18848;18834:13:::1;:24::i;:::-;18928:7;::::0;18905:39:::1;::::0;;-1:-1:-1;;;18905:39:1;;;;18809:49;;-1:-1:-1;18876:85:1::1;::::0;18898:4:::1;::::0;-1:-1:-1;;;18928:7:1;::::1;-1:-1:-1::0;;;;;18928:7:1::1;::::0;18905:37:::1;::::0;18928:7:::1;18905:39:::0;;::::1;::::0;::::1;::::0;;;;;;;;18928:7;18905:39;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;18905:39:1;18946:14;18876:13:::1;:85::i;:::-;18979:51;18993:4;19000:29;:9:::0;19014:14;19000:13:::1;:29::i;:::-;18979:5;:51::i;:::-;18500:615;;;;;19069:31;19083:4;19090:9;19069:5;:31::i;:::-;19129:35;19143:7;19152:2;19156:7;19129:13;:35::i;:::-;19178;19192:7;19201:2;19205:7;19178:13;:35::i;:::-;-1:-1:-1::0;;19259:40:1::1;::::0;;-1:-1:-1;;;19259:40:1;;19293:4:::1;19259:40;::::0;::::1;::::0;;;-1:-1:-1;;;;;19259:25:1;::::1;::::0;-1:-1:-1;;19259:40:1;;;;;::::1;::::0;;;;;;;;:25;:40;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;19259:40:1;19324::::1;::::0;;-1:-1:-1;;;19324:40:1;;19358:4:::1;19324:40;::::0;::::1;::::0;;;19259;;-1:-1:-1;;;;;;19324:25:1;::::1;::::0;-1:-1:-1;;19324:40:1;;;;;19259::::1;::::0;19324;;;;;;;;:25;:40;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;19324:40:1;;-1:-1:-1;19378:27:1::1;19386:8:::0;19324:40;19378:7:::1;:27::i;:::-;19423:5;19419:85;;;19438:6;::::0;;;::::1;;;:66;;19482:22;:8:::0;19495;19482:12:::1;:22::i;:::-;19438:66;;;19447:32;19460:8;19470;19447:12;:32::i;:::-;19430:5;:74:::0;19419:85:::1;19529:38;::::0;;;;;::::1;::::0;::::1;::::0;;;;;-1:-1:-1;;;;;19529:38:1;::::1;::::0;19534:10:::1;::::0;19529:38:::1;::::0;;;;;;;;;::::1;2426:1:19;;;;;;;;1645::::0;2570:7;:22;;;;17533:2041:1;;;:::o;315:39:0:-;;;;;;;;;;;;;;;-1:-1:-1;;315:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3015:148;3087:4;3103:32;3113:10;3125:2;3129:5;3103:9;:32::i;6266:904:1:-;6317:15;6334;6361:16;6380:7;;6361:26;;6420:8;6401:15;:27;6397:767;;6445:17;6464;6493:10;:8;:10::i;:::-;-1:-1:-1;;6527:19:1;;;;;-1:-1:-1;;;6570:19:1;;-1:-1:-1;6397:767:1;;-1:-1:-1;;6397:767:1;;6638:17;6673;6708;6743;6778:18;6814;6849:10;:8;:10::i;:::-;6620:239;;;;;;;;;;;;6883:48;6898:10;6910;6922:8;6883:14;:48::i;:::-;6873:58;;6955:48;6970:10;6982;6994:8;6955:14;:48::i;:::-;6945:58;;7054:5;;7021:30;7034:7;7043;7021:12;:30::i;:::-;:38;7017:137;;;7089:11;7079:21;;;;7128:11;7118:21;;;;7017:137;6397:767;;;;;;;6266:904;;;:::o;831:58::-;884:5;831:58;:::o;10849:198::-;3173:7;;3150:44;;;-1:-1:-1;;;3150:44:1;;;;-1:-1:-1;;;3173:7:1;;;-1:-1:-1;;;;;3173:7:1;;3150:42;;3173:7;3150:44;;;;;;;;;;;;;;3173:7;3150:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3150:44:1;-1:-1:-1;;;;;3136:58:1;:10;:58;3128:84;;;;;-1:-1:-1;;;3128:84:1;;;;;;;;;;;;-1:-1:-1;;;3128:84:1;;;;;;;;;;;;;;;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;10963:6:1::2;::::0;;;::::2;;;10955:39;;;::::0;;-1:-1:-1;;;10955:39:1;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;-1:-1:-1;;;10955:39:1;;;;;;;;;;;;;::::2;;11004:36;11017:10;11029;11004:12;:36::i;:::-;-1:-1:-1::0;;1645:1:19::1;2570:7;:22:::0;10849:198:1:o;25008:412::-;1688:1:19;2267:7;;:19;;2259:63;;;;;-1:-1:-1;;;2259:63:19;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;;;1688:1;2397:7;:18;25093:6:1::1;::::0;25142::::1;::::0;-1:-1:-1;;;;;25093:6:1;;::::1;::::0;25142::::1;25075:15;::::0;25214:13:::1;:11;:13::i;:::-;25264:40;::::0;;-1:-1:-1;;;25264:40:1;;25298:4:::1;25264:40;::::0;::::1;::::0;;;25173:54;;-1:-1:-1;25173:54:1;;-1:-1:-1;25237:83:1::1;::::0;25251:7;;25260:2;;25264:55:::1;::::0;25173:54;;-1:-1:-1;;;;;25264:25:1;::::1;::::0;::::1;::::0;:40;;;;;::::1;::::0;;;;;;;;:25;:40;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;25264:40:1;;:44:::1;:55::i;:::-;25237:13;:83::i;:::-;25357:40;::::0;;-1:-1:-1;;;25357:40:1;;25391:4:::1;25357:40;::::0;::::1;::::0;;;25330:83:::1;::::0;25344:7;;25353:2;;25357:55:::1;::::0;25402:9;;-1:-1:-1;;;;;25357:25:1;::::1;::::0;::::1;::::0;:40;;;;;::::1;::::0;;;;;;;;;:25;:40;::::1;;::::0;::::1;;;;::::0;::::1;25330:83;-1:-1:-1::0;;1645:1:19;2570:7;:22;-1:-1:-1;;;25008:412:1:o;1473:31::-;;;-1:-1:-1;;;1473:31:1;;-1:-1:-1;;;;;1473:31:1;;:::o;12328:322::-;3173:7;;3150:44;;;-1:-1:-1;;;3150:44:1;;;;-1:-1:-1;;;3173:7:1;;;-1:-1:-1;;;;;3173:7:1;;3150:42;;3173:7;3150:44;;;;;;;;;;;;;;3173:7;3150:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3150:44:1;-1:-1:-1;;;;;3136:58:1;:10;:58;3128:84;;;;;-1:-1:-1;;;3128:84:1;;;;;;;;;;;;-1:-1:-1;;;3128:84:1;;;;;;;;;;;;;;;12442:3:::1;12426:12;:19;;12418:47;;;::::0;;-1:-1:-1;;;12418:47:1;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;12418:47:1;;;;;;;;;;;;;::::1;;12514:18;::::0;;12542:33;;;;12590:53:::1;::::0;;;;;::::1;::::0;::::1;::::0;;;;;::::1;::::0;;;;;;;;;::::1;3222:1;12328:322:::0;:::o;1546:30::-;;;-1:-1:-1;;;;;1546:30:1;;:::o;9486:191::-;3173:7;;3150:44;;;-1:-1:-1;;;3150:44:1;;;;-1:-1:-1;;;3173:7:1;;;-1:-1:-1;;;;;3173:7:1;;3150:42;;3173:7;3150:44;;;;;;;;;;;;;;3173:7;3150:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3150:44:1;-1:-1:-1;;;;;3136:58:1;:10;:58;3128:84;;;;;-1:-1:-1;;;3128:84:1;;;;;;;;;;;;-1:-1:-1;;;3128:84:1;;;;;;;;;;;;;;;9577:8:::1;::::0;;9606:15:::1;::::0;::::1;-1:-1:-1::0;;9595:26:1;::::1;::::0;::::1;::::0;;;9636:34:::1;::::0;;9577:8:::1;::::0;;::::1;9636:34:::0;;;::::1;::::0;::::1;::::0;;;;;;::::1;::::0;;;;;;;;::::1;3222:1;9486:191:::0;:::o;3515:725:0:-;3737:15;3725:8;:27;;3717:51;;;;;-1:-1:-1;;;3717:51:0;;;;;;;;;;;;-1:-1:-1;;;3717:51:0;;;;;;;;;;;;;;;3880:16;;-1:-1:-1;;;;;3975:13:0;;;3778:14;3975:13;;;:6;:13;;;;;;;;:15;;-1:-1:-1;3975:15:0;;;;;;3924:77;;799:66;3924:77;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3924:77:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;3914:88;;;;;;-1:-1:-1;;;3818:198:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3795:231;;;;;;;;;4063:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3778:14;;-1:-1:-1;4063:26:0;;;;;-1:-1:-1;;4063:26:0;;;;;;;;;;-1:-1:-1;4063:26:0;;;;;;;;;;;;;;;-1:-1:-1;;4063:26:0;;-1:-1:-1;;4063:26:0;;;-1:-1:-1;;;;;;;4107:30:0;;;;;;:59;;-1:-1:-1;;;;;;4141:25:0;;;;;;;4107:59;4099:93;;;;;-1:-1:-1;;;4099:93:0;;;;;;;;;;;;-1:-1:-1;;;4099:93:0;;;;;;;;;;;;;;;4202:31;4211:5;4218:7;4227:5;4202:8;:31::i;:::-;3515:725;;;;;;;;;:::o;510:73::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;3524:294:1:-;3743:8;;;;;;3775:10;;;;;;;3805:6;;;;;3524:294::o;1582:21::-;;;-1:-1:-1;;;;;1582:21:1;;:::o;13223:382::-;13408:7;;-1:-1:-1;;;13408:7:1;;-1:-1:-1;;;;;13408:7:1;13394:10;:21;13386:47;;;;;-1:-1:-1;;;13386:47:1;;;;;;;;;;;;-1:-1:-1;;;13386:47:1;;;;;;;;;;;;;;;13443:6;:16;;-1:-1:-1;;;;;;13443:16:1;;;-1:-1:-1;;;;;13443:16:1;;;;;;;;;;13469:15;:34;;;;;;;;;;13513:6;:16;;;;;;;;;;13539:6;:16;;;;;;;;;;;;;;13565:33;13513:16;13539;13565:15;:33::i;:::-;13223:382;;;;:::o;25488:231::-;1688:1:19;2267:7;;:19;;2259:63;;;;;-1:-1:-1;;;2259:63:19;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;;;1688:1;2397:7;:18;25572:6:1::1;::::0;25565:39:::1;::::0;;-1:-1:-1;;;25565:39:1;;25598:4:::1;25565:39;::::0;::::1;::::0;;;-1:-1:-1;;;;;;;25572:6:1::1;::::0;-1:-1:-1;;25565:39:1;;;;;::::1;::::0;;;;;;;;25572:6;25565:39;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;25565:39:1;25641:6:::1;::::0;25634:39:::1;::::0;;-1:-1:-1;;;25634:39:1;;25667:4:::1;25634:39;::::0;::::1;::::0;;;25565;;-1:-1:-1;;;;;;;;25641:6:1;;::::1;::::0;-1:-1:-1;;25634:39:1;;;;;25565::::1;::::0;25634;;;;;;;;25641:6;25634:39;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;25634:39:1;;-1:-1:-1;25683:29:1::1;25691:9:::0;25634:39;25683:7:::1;:29::i;7665:310::-:0;947:34;;;;;;;;;;;;;;;;;7825:43;;-1:-1:-1;;;;;7825:43:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;7825:43:1;-1:-1:-1;;;7825:43:1;;;7814:55;;;;-1:-1:-1;;;;7814:10:1;;;7825:43;7814:55;;;7825:43;7814:55;;7825:43;7814:55;;;;;;;;;;-1:-1:-1;;7814:55:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7778:91;;;;7887:7;:57;;;;-1:-1:-1;7899:11:1;;:16;;:44;;;7930:4;7919:24;;;;;;;;;;;;;;;-1:-1:-1;7919:24:1;7899:44;7879:89;;;;;-1:-1:-1;;;7879:89:1;;;;;;;;;;;;-1:-1:-1;;;7879:89:1;;;;;;;;;;;;;;;7665:310;;;;;:::o;471:149:20:-;529:9;558:6;;;:30;;-1:-1:-1;;573:5:20;;;587:1;582;573:5;582:1;568:15;;;;;:20;558:30;550:63;;;;;-1:-1:-1;;;550:63:20;;;;;;;;;;;;-1:-1:-1;;;550:63:20;;;;;;;;;;;;;;329:136;421:5;;;416:16;;;;408:50;;;;;-1:-1:-1;;;408:50:20;;;;;;;;;;;;-1:-1:-1;;;408:50:20;;;;;;;;;;;;;;23314:489:1;23393:9;23415:17;23434;23455:13;:11;:13::i;:::-;23414:54;;;;23478:13;23507:9;23495;:21;23494:57;;23537:14;:7;23549:1;23537:11;:14::i;:::-;23494:57;;;23520:14;:7;23532:1;23520:11;:14::i;:::-;23478:73;-1:-1:-1;23561:13:1;23577:19;23594:1;23577:12;23478:73;23587:1;23577:9;:12::i;:::-;:16;;:19::i;:::-;23561:35;-1:-1:-1;23619:12:1;23634:53;23674:12;23561:35;23684:1;23674:9;:12::i;:::-;23634:35;23644:24;:9;23658;23644:13;:24::i;:::-;23634:5;;:9;:35::i;:::-;:39;;:53::i;:::-;23619:68;-1:-1:-1;23795:1:1;23619:68;23729:56;23749:35;23778:5;23749:24;:9;23763;23749:13;:24::i;:35::-;23745:1;23739:4;:7;:45;23729:9;:56::i;:::-;:63;23728:68;;23314:489;-1:-1:-1;;;;;;;;23314:489:1:o;24358:458::-;24529:4;24545:16;24564:15;24574:4;24564:9;:15::i;:::-;24545:34;;24589:13;24617:8;24606;:19;24605:53;;24645:13;:6;24656:1;24645:10;:13::i;:::-;24605:53;;;24629:13;:6;24640:1;24629:10;:13::i;:::-;24589:69;-1:-1:-1;24668:17:1;24688:19;24589:69;24698:8;24688:9;:19::i;:::-;24668:39;-1:-1:-1;24805:4:1;24724:77;24799:1;24784:12;:5;24794:1;24784:9;:12::i;:::-;24783:17;24724:54;24754:23;:8;24767:9;24754:12;:23::i;:::-;24725;:8;24738:9;24725:12;:23::i;24724:77::-;:85;;;24358:458;-1:-1:-1;;;;;;;;;24358:458:1:o;13804:183::-;13875:8;:28;;-1:-1:-1;;13875:28:1;-1:-1:-1;;;;;13875:28:1;;;;;;;13913;;-1:-1:-1;;;13913:28:1;;;;;;;;;;;;;13956:24;;;13961:8;;;13956:24;;13971:8;;;;;;;13956:24;;;;;;;;;;;;;;;;;13804:183;;:::o;2393:199:0:-;-1:-1:-1;;;;;2506:16:0;;;;;;;:9;:16;;;;;;;;:25;;;;;;;;;;;;;:33;;;2554:31;;;;;;;;;;;;;;;;;2393:199;;;:::o;11319:761:1:-;11433:1;11419:10;:15;;;;:34;;;;;11452:1;11438:10;:15;;;;11419:34;:59;;;;;11471:7;11457:10;:21;;;;11419:59;:84;;;;;11496:7;11482:10;:21;;;;11419:84;11398:148;;;;;-1:-1:-1;;;11398:148:1;;;;;;;;;;;;-1:-1:-1;;;11398:148:1;;;;;;;;;;;;;;;11634:7;;11582:15;;11615:26;;;11607:65;;;;;-1:-1:-1;;;11607:65:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;11683:17;11702;11723:13;:11;:13::i;:::-;11682:54;;;;11746:30;11755:9;11766;11746:8;:30::i;:::-;-1:-1:-1;11798:9:1;;;-1:-1:-1;;;;;11798:9:1;;;;;;;-1:-1:-1;;11786:21:1;;;;;;;11817;;;-1:-1:-1;;;11829:9:1;;;;;;-1:-1:-1;;;11817:21:1;;;;;;;-1:-1:-1;;11848:22:1;;;;;;;-1:-1:-1;;;;11880:22:1;;;;;;;;;;;11912:9;:27;;;11977:5;;11959:23;;11949:7;:33;;;-1:-1:-1;11997:76:1;;12010:9;;;11997:76;;12021:9;;;;;-1:-1:-1;11997:76:1;;;12032:9;;;;;11997:76;;;;12043:9;;;;;;;-1:-1:-1;11997:76:1;;;;;;;;;;;;;;;;;;;;;;;;11319:761;;;;;:::o;2598:249:0:-;-1:-1:-1;;;;;2724:15:0;;;;;;:9;:15;;;;;;:26;;2744:5;2724:19;:26::i;:::-;-1:-1:-1;;;;;2706:15:0;;;;;;;:9;:15;;;;;;:44;;;;2776:13;;;;;;;:24;;2794:5;2776:17;:24::i;:::-;-1:-1:-1;;;;;2760:13:0;;;;;;;:9;:13;;;;;;;;;:40;;;;2815:25;;;;;;;2760:13;;2815:25;;;;;;;;;;;;;2598:249;;;:::o;14349:1012:1:-;14483:7;;14460:39;;;-1:-1:-1;;;14460:39:1;;;;14422:10;;;;-1:-1:-1;;;14483:7:1;;;-1:-1:-1;;;;;14483:7:1;;14460:37;;14483:7;14460:39;;;;;;;;;;;;;;14483:7;14460:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;14460:39:1;14561:5;;-1:-1:-1;;;;;14517:19:1;;;;;;-1:-1:-1;14460:39:1;;-1:-1:-1;14561:5:1;14591:764;;14620:9;;14616:674;;14650:15;14667;14686:21;:19;:21::i;:::-;14744:6;;14649:58;;-1:-1:-1;14649:58:1;-1:-1:-1;14725:16:1;;14744:6;;;;;:128;;14837:35;14847:24;:9;14861;14847:13;:24::i;14837:35::-;14744:128;;;14773:41;14783:30;14796:7;14805;14783:12;:30::i;14773:41::-;14725:147;;14890:16;14909:15;14919:4;14909:9;:15::i;:::-;14890:34;;14957:8;14946;:19;14942:334;;;14989:17;15009:46;15053:1;15009:39;15025:22;:8;15038;15025:12;:22::i;:::-;15009:11;;;:15;:39::i;:46::-;14989:66;-1:-1:-1;15077:19:1;15099:29;15112:15;:8;15125:1;15112:12;:15::i;:::-;15099:8;;:12;:29::i;:::-;15077:51;;15150:17;15182:11;15170:9;:23;;;;;;;-1:-1:-1;15219:13:1;;15215:42;;15234:23;15240:5;15247:9;15234:5;:23::i;:::-;14942:334;;;;14616:674;;;;;14591:764;;;15310:9;;15306:49;;15343:1;15335:5;:9;15306:49;14349:1012;;;;;;:::o;349:301:18:-;397:9;426:1;422;:5;418:226;;;-1:-1:-1;447:1:18;482;478;474:5;;:9;497:89;508:1;504;:5;497:89;;;533:1;529:5;;570:1;565;561;557;:5;;;;;;:9;556:15;;;;;;552:19;;497:89;;;418:226;;;;606:6;;602:42;;-1:-1:-1;632:1:18;602:42;349:301;;;:::o;1973:200:0:-;2048:11;;:22;;2064:5;2048:15;:22::i;:::-;2034:11;:36;-1:-1:-1;;;;;2096:13:0;;;;;;:9;:13;;;;;;:24;;2114:5;2096:17;:24::i;:::-;-1:-1:-1;;;;;2080:13:0;;;;;;:9;:13;;;;;;;;:40;;;;2135:31;;;;;;;2080:13;;;;2135:31;;;;;;;;;;1973:200;;:::o;131:103:18:-;189:9;218:1;214;:5;:13;;226:1;214:13;;;-1:-1:-1;222:1:18;;210:17;-1:-1:-1;131:103:18:o;7176:208:1:-;7225:15;7242;7290:11;:9;:11::i;:::-;7311:10;:28;;;7349;;;-1:-1:-1;;;7349:28:1;-1:-1:-1;;;;7311:28:1;;;-1:-1:-1;;;7311:28:1;-1:-1:-1;;;;7311:28:1;;;;;;;7349;;;;7311;;7349;;-1:-1:-1;7311:28:1;-1:-1:-1;7176:208:1:o;1082:130:20:-;1140:7;1166:39;1170:1;1173;1166:39;;;;;;;;;;;;;;;;;:3;:39::i;2179:208:0:-;-1:-1:-1;;;;;2260:15:0;;;;;;:9;:15;;;;;;:26;;2280:5;2260:19;:26::i;:::-;-1:-1:-1;;;;;2242:15:0;;;;;;:9;:15;;;;;:44;2310:11;;:22;;2326:5;2310:15;:22::i;:::-;2296:11;:36;2347:33;;;;;;;;2370:1;;-1:-1:-1;;;;;2347:33:0;;;;;;;;;;;;2179:208;;:::o;4494:472:1:-;4786:9;;;-1:-1:-1;;;4786:9:1;;;;;-1:-1:-1;;;4818:9:1;;;;;4850;;;;-1:-1:-1;;;4882:9:1;;;;;-1:-1:-1;;;4915:10:1;;;;;-1:-1:-1;;;4949:10:1;;;;;;4494:472::o;5311:713::-;5466:9;;5431:7;;5489:15;;;;;;;;5485:533;;;5599:149;5640:90;5715:14;:3;5723:5;5715:7;:14::i;:::-;5640:70;5683:26;:15;5703:5;5683:19;:26::i;:::-;5641:36;5661:15;5641;;;;5661;;;;5641:19;:36;:::i;5640:90::-;5599:15;;;;;:149;:19;:149;:::i;:::-;5576:172;;;;;5485:533;5858:149;5899:90;5974:14;:3;5982:5;5974:7;:14::i;:::-;5899:70;5942:26;:15;5962:5;5942:19;:26::i;:::-;5900:36;5920:15;5900;;;;5920;;;;5900:19;:36;:::i;5899:90::-;5858:15;;;;;:149;:19;:149;:::i;1076:415:0:-;1217:18;1269:7;-1:-1:-1;;;;;1262:22:0;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1262:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;1262:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1262:24:0;;;;;;;;;;;;-1:-1:-1;1262:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1262:24:0;;;;-1:-1:-1;;;1293:24:0;;;-1:-1:-1;;;;;1293:22:0;;;-1:-1:-1;1293:22:0;;-1:-1:-1;1293:24:0;;;;;-1:-1:-1;1293:24:0;;;;;;;:22;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1293:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;1293:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1293:24:0;;;;;;;;;;;;-1:-1:-1;1293:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1245:73;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1245:73:0;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1245:73:0;;;;;;;;;;;-1:-1:-1;;;1245:73:0;;;;;;;;;;;;;;;;;-1:-1:-1;1245:73:0;;;;;;;;;;;;;-1:-1:-1;;1245:73:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1217:102;;1385:4;1343:47;;;;;;-1:-1:-1;;;1343:47:0;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1343:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1329:4;:62;;;;;;;;;;;;:::i;:::-;-1:-1:-1;1417:33:0;;-1:-1:-1;;;1417:33:0;;;;;;;;;1445:4;;1417:33;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1417:33:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1401:6;:50;;;;;;;;;;;;:::i;:::-;;1461:23;:21;:23::i;:::-;1076:415;;;:::o;188:135:20:-;280:5;;;275:16;;;;267:49;;;;;-1:-1:-1;;;267:49:20;;;;;;;;;;;;-1:-1:-1;;;267:49:20;;;;;;;;;;;;;;1694:302;1810:7;1844:12;1837:5;1829:28;;;;-1:-1:-1;;;1829:28:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1867:9;1883:1;1879;:5;;;;;;;1694:302;-1:-1:-1;;;;;1694:302:20:o;1497:470:0:-;1549:15;1608:9;1597:20;;1706:95;1835:4;1819:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1819:22:0;;;;;;;;;1869:10;;;;;;;;-1:-1:-1;;;1869:10:0;;;;;1678:272;;;;;;;;;;;;;1859:21;1678:272;;;;;;;;;;;1931:4;1678:272;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1655:305:0;;;;;1636:16;:324;1497:470::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;

Swarm Source

ipfs://4dbf543a2bd3ad0712169d0b39f3521aca3ee7132f62965d35c4ab3664c5ec21
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.