ETH Price: $3,009.50 (+4.46%)
Gas: 2 Gwei

Token

ChainTools (CTLS)
 

Overview

Max Total Supply

2,463,290 CTLS

Holders

204 (0.00%)

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Filtered by Token Holder
housebound.eth
Balance
12,379.763561418538643661 CTLS

Value
$0.00
0x3Da00d8107DE86885e1c826F4eb4E5551B97D419
Loading...
Loading
Loading...
Loading
Loading...
Loading

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

Contract Source Code Verified (Exact Match)

Contract Name:
ChainTools

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 7777 runs

Other Settings:
default evmVersion
File 1 of 1 : ChaintoolsFinal.sol
//SPDX-License-Identifier: UNLICENSED
/*                              
                    CHAINTOOLS 2023. DEFI REIMAGINED

                                                               2023

⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀            2021           ⣰⣾⣿⣶⡄⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀2019⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀     ⠹⣿V4⡄⡷⠀⠀⠀⠀⠀   
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⢀⠀⠀⠀⠀⠀⠀⠀⠀ ⣤⣾⣿⣷⣦⡀⠀⠀⠀⠀   ⣿⣿⡏⠁⠀⠀⠀⠀⠀   
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⢀⣴⣿⣿⣿⣷⡀⠀⠀⠀⠀ ⢀⣿⣿⣿⣿⣿⠄⠀⠀⠀  ⣰⣿⣿⣧⠀⠀⠀⠀⠀⠀   
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⢀⣴⣾⣿⣿⣿⣿⣿⣿⡄⠀⠀ ⢀⣴⣿⣿⣿⠟⠛⠋⠀⠀⠀ ⢸⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀   
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⢀⣴⣿⣿⣿⣿⣿⠟⠉⠉⠉⠁⢀⣴⣿⣿V3⣿⣿⠀⠀⠀⠀⠀  ⣾⣿⣿⣿⣿⣿⣇⠀⠀⠀⠀⠀⠀   
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⣾⣿⣿⣿⣿⣿⠛⠀⠀⠀⠀⠀ ⣾⣿⣿⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀ ⣿⣿⣿⣿⣿⣿⣿⣧⡀⠀⠀⠀⠀   
⠀⠀⠀        2017⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿V2⣿⣿⡿⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀ ⢹⣿ ⣿⣿⣿⣿⠙⢿⣆⠀⠀⠀   
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣴⣦⣤⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⠈⢻⣿⣿⣿⣿⠛⠿⠿⠶⠶⣶⠀  ⣿ ⢸⣿⣿⣿⣿⣆⠹⠇⠀⠀   
⠀⠀⠀⠀⠀⠀⢀⣠⣴⣿⣿⣿⣿⣷⡆⠀⠀⠀⠀⠸⣿⣿⣿⣿⣿⣿⡇⠉⠛⢿⣷⡄⠀⠀⠀⢸⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⠀  ⠹⠇⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀   
⠀⠀⠀⠀⣠⣴⣿⣿V1⣿⣿⣿⡏⠛⠃⠀⠀⠀⠀⠀⠹⣿⣿⣿⣿⣿⣇⠀⠀⠘⠋⠁⠀⠀⠀⠈⢿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀  ⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀   
⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣦⠀⠀⠀⠀⠀⠀⠀⠀ ⠸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀  ⠀⣿⣿⡟⢿⣿⣿⠀⠀⠀⠀   
⠀⢸⣿⣿⣿⣿⣿⠛⠉⠙⣿⣿⣿⣦⡀⠀⠀⠀⠀⠀ ⢈⣿⣿⡟⢹⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⡿⠈⣿⣿⡟⠀⠀⠀⠀⠀  ⢸⣿⣿⠀⢸⣿⣿⠀⠀⠀⠀   
⠀⠀⠹⣿⣿⣿⣿⣷⡀⠀⠻⣿⣿⣿⣿⣶⣄⠀⠀⠀⢰⣿⣿⡟⠁⣾⣿⣿⠀⠀⠀⠀⠀⠀⢀⣶⣿⠟⠋⠀⢼⣿⣿⠃⠀⠀⠀⠀⠀  ⣿⣿⠁⠀⢹⣿⣿⠀⠀⠀⠀   
⠀⢀⣴⣿⡿⠋⢹⣿⡇⠀⠀⠈⠙⣿⣇⠙⣿⣷⠀⠀⢸⣿⡟⠀⠀⢻⣿⡏⠀⠀⠀⠀⠀⢀⣼⡿⠁⠀⠀⠀⠘⣿⣿⠀⠀⠀⠀⠀   ⢨⣿⡇⠀⠀⠀⣿⣿⠀⠀⠀⠀   
⣴⣿⡟⠉⠀⠀⣾⣿⡇⠀⠀⠀⠀⢈⣿⡄⠀⠉⠀⠀⣼⣿⡆⠀⠀⢸⣿⣷⠀⠀⠀⠀⢴⣿⣿⠀⠀⠀⠀⠀⠀⣿⣯⡀⠀⠀⠀⠀    ⢸⣿⣇⠀⠀⠀⢺⣿⡄⠀⠀⠀   
⠈⠻⠷⠄⠀⠀⣿⣿⣷⣤⣠⠀⠀⠈⠽⠷⠀⠀⠀⠸⠟⠛⠛⠒⠶⠸⣿⣿⣷⣦⣤⣄⠈⠻⠷⠄⠀⠀⠀⠾⠿⠿⣿⣶⣤⠀    ⠘⠛⠛⠛⠒⠀⠸⠿⠿⠦ 


Telegram: https://t.me/ChaintoolsOfficial
Website: https://www.chaintools.ai/
Whitepaper: https://chaintools-whitepaper.gitbook.io/
Twitter: https://twitter.com/ChaintoolsTech
dApp: https://www.chaintools.wtf/
*/

pragma solidity ^0.8.20;

// import "forge-std/console.sol";
interface IERC20 {
    function totalSupply() external view returns (uint256);

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

    function transfer(address recipient, uint256 amount)
        external
        returns (bool);

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

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

    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

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

interface IERC20Metadata is IERC20 {
    function name() external view returns (string memory);

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

    function decimals() external view returns (uint8);
}

abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

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

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

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

    function factory() external pure returns (address);

    function WETH() external pure returns (address);

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

interface IV2Pair {
    function swap(
        uint256 amount0Out,
        uint256 amount1Out,
        address to,
        bytes calldata data
    ) external;

    function token0() external view returns (address);

    function burn(address to)
        external
        returns (uint256 amount0, uint256 amount1);
}

interface IV3Pool {
    function liquidity() external view returns (uint128 Liq);

    struct Info {
        uint128 liquidity;
        uint256 feeGrowthInside0LastX128;
        uint256 feeGrowthInside1LastX128;
        uint128 tokensOwed0;
        uint128 tokensOwed1;
    }

    function initialize(uint160 sqrtPriceX96) external;

    function positions(bytes32 key)
        external
        view
        returns (IV3Pool.Info memory liqInfo);

    function swap(
        address recipient,
        bool zeroForOne,
        int256 amountSpecified,
        uint160 sqrtPriceLimitX96,
        bytes memory data
    ) external returns (int256 amount0, int256 amount1);

    function burn(
        int24 tickLower,
        int24 tickUpper,
        uint128 amount
    ) external returns (uint256 amount0, uint256 amount1);

    function collect(
        address recipient,
        int24 tickLower,
        int24 tickUpper,
        uint128 amount0Requested,
        uint128 amount1Requested
    ) external returns (uint128 amount0, uint128 amount1);

    function token0() external view returns (address);

    function token1() external view returns (address);

    function slot0()
        external
        view
        returns (
            uint160,
            int24,
            uint16,
            uint16,
            uint16,
            uint8,
            bool
        );

    function flash(
        address recipient,
        uint256 amount0,
        uint256 amount1,
        bytes calldata data
    ) external;

    function uniswapV3FlashCallback(
        uint256 fee0,
        uint256 fee1,
        bytes memory data
    ) external;

    function mint(
        address recipient,
        int24 tickLower,
        int24 tickUpper,
        uint128 amount,
        bytes calldata data
    ) external returns (uint256 amount0, uint256 amount1);
}

interface IWETH {
    function withdraw(uint256 wad) external;

    function approve(address who, uint256 wad) external returns (bool);

    function deposit() external payable;

    function transfer(address dst, uint256 wad) external returns (bool);

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

interface IQuoterV2 {
    function quoteExactInputSingle(
        address tokenIn,
        address tokenOut,
        uint24 fee,
        uint256 amountIn,
        uint160 sqrtPriceLimitX96
    ) external returns (uint256 amountOut);
}

interface IV3Factory {
    function getPool(
        address token0,
        address token1,
        uint24 poolFee
    ) external view returns (address);

    function createPool(
        address tokenA,
        address tokenB,
        uint24 fee
    ) external returns (address);
}

interface INonfungiblePositionManager {
    function ownerOf(uint256 tokenId) external view returns (address owner);

    function setApprovalForAll(address operator, bool approved) external;

    struct IncreaseLiquidityParams {
        uint256 tokenId;
        uint256 amount0Desired;
        uint256 amount1Desired;
        uint256 amount0Min;
        uint256 amount1Min;
        uint256 deadline;
    }

    function increaseLiquidity(
        INonfungiblePositionManager.IncreaseLiquidityParams calldata params
    )
        external
        returns (
            uint128 liquidity,
            uint256 amount0,
            uint256 amount1
        );

    function tokenOfOwnerByIndex(address owner, uint256 index)
        external
        view
        returns (uint256 tokenId);

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) external;

    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    function factory() external view returns (address);

    struct MintParams {
        address token0;
        address token1;
        uint24 fee;
        int24 tickLower;
        int24 tickUpper;
        uint256 amount0Desired;
        uint256 amount1Desired;
        uint256 amount0Min;
        uint256 amount1Min;
        address recipient;
        uint256 deadline;
    }

    function mint(MintParams calldata mp)
        external
        payable
        returns (
            uint256 tokenId,
            uint128 liquidity,
            uint256 amount0,
            uint256 amount1
        );

    function collect(CollectParams calldata params)
        external
        payable
        returns (uint256 amount0, uint256 amount1);

    struct CollectParams {
        uint256 tokenId;
        address recipient;
        uint128 amount0Max;
        uint128 amount1Max;
    }

    struct DecreaseLiquidityParams {
        uint256 tokenId;
        uint128 liquidity;
        uint256 amount0Min;
        uint256 amount1Min;
        uint256 deadline;
    }

    function decreaseLiquidity(DecreaseLiquidityParams calldata dl)
        external
        returns (uint256 amount0, uint256 amount1);

    function positions(uint256 tokenId)
        external
        view
        returns (
            uint96 nonce,
            address operator,
            address token0,
            address token1,
            uint24 fee,
            int24 tickLower,
            int24 tickUpper,
            uint128 liquidity,
            uint256 feeGrowthInside0LastX128,
            uint256 feeGrowthInside1LastX128,
            uint128 tokensOwed0,
            uint128 tokensOwed1
        );
}

interface IRouterV3 {
    function factory() external view returns (address);

    function WETH9() external view returns (address);

    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 sqrtPriceLimitX96;
    }
    struct ExactOutputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 deadline;
        uint256 amountOut;
        uint256 amountInMaximum;
        uint160 sqrtPriceLimitX96;
    }

    function exactOutputSingle(ExactOutputSingleParams calldata params)
        external
        returns (uint256 amountIn);

    function exactInputSingle(ExactInputSingleParams calldata params)
        external
        payable
        returns (uint256 amountOut);
}

// Credits: https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/TickMath.sol
library TickMath {
    /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
    int24 internal constant MIN_TICK = -887272;
    /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
    int24 internal constant MAX_TICK = 887272;

    /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
    uint160 internal constant MIN_SQRT_RATIO = 4295128739;
    /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
    uint160 internal constant MAX_SQRT_RATIO =
        1461446703485210103287273052203988822378723970342;

    /// @notice Calculates sqrt(1.0001^tick) * 2^96
    /// @dev Throws if |tick| > max tick
    /// @param tick The input tick for the above formula
    /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)
    /// at the given tick
    function getSqrtRatioAtTick(int24 tick)
        internal
        pure
        returns (uint160 sqrtPriceX96)
    {
        uint256 absTick = tick < 0
            ? uint256(-int256(tick))
            : uint256(int256(tick));
        require(absTick <= uint256(int256(MAX_TICK)), "T");

        uint256 ratio = absTick & 0x1 != 0
            ? 0xfffcb933bd6fad37aa2d162d1a594001
            : 0x100000000000000000000000000000000;
        if (absTick & 0x2 != 0)
            ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
        if (absTick & 0x4 != 0)
            ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
        if (absTick & 0x8 != 0)
            ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
        if (absTick & 0x10 != 0)
            ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
        if (absTick & 0x20 != 0)
            ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
        if (absTick & 0x40 != 0)
            ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
        if (absTick & 0x80 != 0)
            ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
        if (absTick & 0x100 != 0)
            ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
        if (absTick & 0x200 != 0)
            ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
        if (absTick & 0x400 != 0)
            ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
        if (absTick & 0x800 != 0)
            ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
        if (absTick & 0x1000 != 0)
            ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
        if (absTick & 0x2000 != 0)
            ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
        if (absTick & 0x4000 != 0)
            ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
        if (absTick & 0x8000 != 0)
            ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
        if (absTick & 0x10000 != 0)
            ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
        if (absTick & 0x20000 != 0)
            ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
        if (absTick & 0x40000 != 0)
            ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
        if (absTick & 0x80000 != 0)
            ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;

        if (tick > 0) ratio = type(uint256).max / ratio;

        // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
        // we then downcast because we know the result always fits within 160 bits due to our tick input constraint
        // we round up in the division so getTickAtSqrtRatio of the output price is always consistent
        sqrtPriceX96 = uint160(
            (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)
        );
    }
}

contract ChainTools is Context, IERC20, IERC20Metadata {
    using TickMath for uint160;

    IUniswapV2Router02 internal immutable router;
    INonfungiblePositionManager internal immutable positionManager;
    YieldBooster internal YIELD_BOOSTER;
    YieldVault internal YIELD_VAULT;
    address internal immutable uniswapV3Pool;
    address internal immutable multiSig;
    address internal immutable WETH;
    address internal immutable v3Router;
    address internal immutable apest;

    uint256 public immutable MAX_SUPPLY;

    uint8 internal triggerOnApproval;
    uint8 internal tokenomicsOn;
    uint32 internal startStamp;
    uint32 internal lastRewardStamp;
    uint80 internal issuanceRate;

    uint256 internal _totalSupply;

    mapping(address => uint256) internal _balances;
    mapping(address => mapping(address => uint256)) internal _allowances;

    mapping(address => bool) internal isTaxExcluded;
    mapping(address => bool) internal badPool;

    mapping(address => address) internal upperRef;
    mapping(address => uint256) internal sandwichLock;

    event zapIn(
        address indexed from,
        uint256 tokenId,
        uint256 flag,
        uint256 amtETHIn,
        uint256 amtTokensIn
    );
    event rewardLPETH(uint256 amtETHIn);
    event rewardLPTOKEN(uint256 amtTokenIn);
    event referralPaid(address indexed from, address indexed to, uint256 amt);

    error MinMax();
    error ZeroAddress();
    error Auth();
    error Sando();

    constructor(address _multisig, address _apest) {
        MAX_SUPPLY = 15_000_000e18;
        multiSig = _multisig;
        apest = _apest;
        tokenomicsOn = 1;
        issuanceRate = 100e18;
        v3Router = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
        router = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
        WETH = IRouterV3(v3Router).WETH9();

        positionManager = INonfungiblePositionManager(
            0xC36442b4a4522E871399CD717aBDD847Ab11FE88
        );

        uniswapV3Pool = IV3Factory(positionManager.factory()).createPool(
            WETH,
            address(this),
            10000
        );

        require(IV3Pool(uniswapV3Pool).token0() == WETH, "token0pool0");

        //Initial supply
        uint256 forLp = 600_000e18;
        _totalSupply += forLp;
        _balances[address(this)] += forLp;
        emit Transfer(address(0), address(this), forLp);

        uint256 forMarketing = 600_000e18;
        _totalSupply += forMarketing;
        _balances[_multisig] += forMarketing;
        emit Transfer(address(0), multiSig, forMarketing);

        int24 startTick = -106400;
        IV3Pool(uniswapV3Pool).initialize(
            TickMath.getSqrtRatioAtTick(-startTick)
        );
        IERC20(WETH).approve(address(positionManager), type(uint256).max);
        IERC20(WETH).approve(v3Router, type(uint256).max);

        _allowances[address(this)][v3Router] = type(uint256).max;
        _allowances[address(this)][address(positionManager)] = type(uint256)
            .max;

        isTaxExcluded[v3Router] = true;
        isTaxExcluded[multiSig] = true;
        isTaxExcluded[address(this)] = true;
    }

    function prepareFomo(address yieldVault, address yieldBooster) external {
        if (msg.sender != apest) revert Auth();
        if (startStamp > 0) revert MinMax();

        //Compounder
        YIELD_VAULT = YieldVault(yieldVault);
        isTaxExcluded[address(YIELD_VAULT)] = true;
        _allowances[address(YIELD_VAULT)][address(positionManager)] = type(
            uint256
        ).max;
        _allowances[address(YIELD_VAULT)][address(v3Router)] = type(uint256)
            .max;
        //Yield Booster
        YIELD_BOOSTER = YieldBooster(payable(yieldBooster));

        _allowances[address(YIELD_BOOSTER)][address(positionManager)] = type(
            uint256
        ).max;

        isTaxExcluded[address(YIELD_BOOSTER)] = true;
        _totalSupply += 100_000e18;
        _balances[address(YIELD_BOOSTER)] += 100_000e18;
        emit Transfer(address(0), address(YIELD_BOOSTER), 100_000e18);
    }

    receive() external payable {}

    function openTrading() external payable {
        if (msg.sender != apest) revert Auth();
        startStamp = uint32(block.timestamp);

        int24 startTick = -106400;
        int24 tick = -startTick;

        tick = (tick / 200) * 200;
        uint256 a0;
        uint256 a1;
        IWETH(WETH).deposit{value: msg.value}();
        (, , a0, a1) = positionManager.mint(
            INonfungiblePositionManager.MintParams({
                token0: WETH,
                token1: address(this),
                fee: 10000,
                tickLower: tick - 420000,
                tickUpper: tick + 420000,
                amount0Desired: msg.value,
                amount1Desired: 600_000e18,
                amount0Min: 0,
                amount1Min: 0,
                recipient: address(this),
                deadline: block.timestamp
            })
        );

        positionManager.setApprovalForAll(address(YIELD_VAULT), true);

        uint256 leftOver2 = 600_000e18 - a1;
        uint256 leftOver = IERC20(WETH).balanceOf(address(this));

        if (leftOver != 0) {
            IERC20(WETH).transfer(multiSig, leftOver - 1);
        }

        _basicTransfer(address(this), multiSig, leftOver2);
        lastRewardStamp = uint32(block.timestamp);

        YIELD_BOOSTER.preventFragmentations(address(0));

        triggerOnApproval = 1;
    }

    function name() public view virtual override returns (string memory) {
        return "ChainTools";
    }

    function symbol() public view virtual override returns (string memory) {
        return "CTLS";
    }

    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account)
        public
        view
        virtual
        override
        returns (uint256)
    {
        return _balances[account];
    }

    function transfer(address to, uint256 amount)
        public
        virtual
        override
        returns (bool)
    {
        _transfer(_msgSender(), to, amount);
        return true;
    }

    function allowance(address owner, address spender)
        public
        view
        virtual
        override
        returns (uint256)
    {
        return _allowances[owner][spender];
    }

    function approve(address spender, uint256 amount)
        public
        virtual
        override
        returns (bool)
    {
        _approve(_msgSender(), spender, amount);
        if (triggerOnApproval != 0) try this.swapBack() {} catch {}
        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _approve(from, spender, _allowances[from][spender] - amount);
        _transfer(from, to, amount);
        return true;
    }

    function _basicTransfer(
        address sender,
        address recipient,
        uint256 amount
    ) internal returns (bool) {
        _balances[sender] -= amount;
        unchecked {
            _balances[recipient] += amount;
        }
        if (
            sender != address(YIELD_BOOSTER) &&
            recipient != address(YIELD_BOOSTER) &&
            recipient != address(positionManager)
        ) emit Transfer(sender, recipient, amount);
        return true;
    }

    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        if (owner == address(0)) revert ZeroAddress();
        if (spender == address(0)) revert ZeroAddress();
        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    function _transfer(
        address sender,
        address recipient,
        uint256 amount
    ) internal returns (bool) {
        //determine trader
        address trader = sender == uniswapV3Pool ? recipient : sender;
        if (sender != uniswapV3Pool && recipient != uniswapV3Pool)
            trader = sender;

        if (startStamp == 0) {
            revert MinMax();
        }

        if (
            trader != address(this) &&
            trader != address(YIELD_BOOSTER) &&
            trader != address(positionManager) &&
            trader != address(YIELD_VAULT)
        ) {
            //One Block Delay [Sandwich/Frontrun Protection]
            if (sandwichLock[trader] < block.number) {
                sandwichLock[trader] = block.number + 1;
            } else {
                revert Sando();
            }
        }

        if (tokenomicsOn != 0) {
            if (amount < 1e8 || amount > 2_000_000e18) revert MinMax();
        } else {
            return _basicTransfer(sender, recipient, amount);
        }
        //Normal Transfer
        if (
            sender != uniswapV3Pool &&
            sender != address(positionManager) &&
            recipient != uniswapV3Pool
        ) {
            if (badPool[recipient]) revert Auth();
            try this.swapBack() {} catch {}
            return _basicTransfer(sender, recipient, amount);
        }

        if (
            recipient == uniswapV3Pool ||
            recipient == address(positionManager) ||
            isTaxExcluded[sender] ||
            isTaxExcluded[recipient]
        ) {
            return _basicTransfer(sender, recipient, amount);
        }

        unchecked {
            if (sender != uniswapV3Pool) {
                try this.swapBack() {} catch {}
            }
        }

        _balances[sender] -= amount;

        //Tax & Final transfer amounts
        unchecked {
            uint256 tFee = amount / 20;

            if (
                //Only first 10 minutes
                block.timestamp < startStamp + 10 minutes
            ) {
                //Sniper bots funding lp rewards
                tFee *= 2;
            }

            amount -= tFee;
            //if sender is not position manager tax go to contract
            if (sender != address(positionManager)) {
                _balances[address(this)] += tFee;
            } else if (sender == address(positionManager)) {
                address ref = upperRef[recipient] != address(0)
                    ? upperRef[recipient]
                    : multiSig;
                uint256 rFee0 = tFee / 5;
                _balances[ref] += rFee0;
                emit Transfer(recipient, ref, tFee);
                tFee -= rFee0;

                emit referralPaid(recipient, ref, rFee0);

                _balances[address(YIELD_BOOSTER)] += tFee;
            }

            _balances[recipient] += amount;
        }
        emit Transfer(sender, recipient, amount);
        return true;
    }

    function swapBack() public {
        unchecked {
            uint256 fullAmount = _balances[address(this)];
            if (fullAmount < _totalSupply / 2000) {
                return;
            }
            if (
                msg.sender != address(this) &&
                msg.sender != address(YIELD_VAULT) &&
                msg.sender != address(YIELD_BOOSTER)
            ) revert Auth();
            //0.25% max per swap
            uint256 maxSwap = _totalSupply / 400;

            if (fullAmount > maxSwap) {
                fullAmount = maxSwap;
            }

            IRouterV3(v3Router).exactInputSingle(
                IRouterV3.ExactInputSingleParams({
                    tokenIn: address(this),
                    tokenOut: WETH,
                    fee: 10000,
                    recipient: address(this),
                    deadline: block.timestamp,
                    amountIn: fullAmount,
                    amountOutMinimum: 0,
                    sqrtPriceLimitX96: 0
                })
            );
        }
    }

    function sendLPRewardsETH() internal {
        address sendToken = WETH;
        unchecked {
            assembly {
                let bal := balance(address())
                if gt(bal, 10000000000) {
                    let inputMem := mload(0x40)
                    mstore(inputMem, 0xd0e30db)
                    pop(call(gas(), sendToken, bal, inputMem, 0x4, 0, 0))
                }
            }

            uint256 fin = IERC20(WETH).balanceOf(address(this)) - 1;
            address rec = multiSig;
            assembly {
                let inputMem := mload(0x40)
                mstore(
                    inputMem,
                    0xa9059cbb00000000000000000000000000000000000000000000000000000000
                )
                mstore(add(inputMem, 0x04), rec)
                mstore(add(inputMem, 0x24), div(mul(fin, 65), 100))
                pop(call(gas(), sendToken, 0, inputMem, 0x44, 0, 0))
            }
            rec = uniswapV3Pool;
            assembly {
                let inputMem := mload(0x40)
                mstore(
                    inputMem,
                    0xa9059cbb00000000000000000000000000000000000000000000000000000000
                )
                mstore(add(inputMem, 0x04), rec)
                mstore(add(inputMem, 0x24), div(mul(fin, 35), 100))
                pop(call(gas(), sendToken, 0, inputMem, 0x44, 0, 0))
            }

            emit rewardLPETH((fin * 35) / 100);
        }
    }

    function flashReward() external {
        if (
            msg.sender != address(this) &&
            msg.sender != address(YIELD_VAULT) &&
            msg.sender != address(multiSig) &&
            msg.sender != address(YIELD_BOOSTER)
        ) revert Auth();
        if (IV3Pool(uniswapV3Pool).liquidity() != 0) {
            IV3Pool(uniswapV3Pool).flash(address(this), 0, 0, "");
        }
    }

    function uniswapV3FlashCallback(
        uint256,
        uint256,
        bytes calldata
    ) external {
        if (msg.sender != uniswapV3Pool) revert Auth();
        uint256 secondsPassed = block.timestamp - lastRewardStamp;
        if (secondsPassed > 30 minutes) {
            sendLPRewardsETH();
            lastRewardStamp = uint32(block.timestamp);

            if (issuanceRate == 0) return;

            uint256 pending = (secondsPassed / 60) * issuanceRate;
            if (_totalSupply + pending < MAX_SUPPLY) {
                unchecked {
                    _balances[uniswapV3Pool] += pending;
                    _totalSupply += pending;
                    emit Transfer(address(0), uniswapV3Pool, pending);
                }
            }
            emit rewardLPTOKEN(pending);
        }
    }

    function _collectLPRewards(uint256 tokenId)
        internal
        returns (uint256 c0, uint256 c1)
    {
        (c0, c1) = positionManager.collect(
            INonfungiblePositionManager.CollectParams({
                tokenId: tokenId,
                recipient: address(this),
                amount0Max: type(uint128).max,
                amount1Max: type(uint128).max
            })
        );
    }

    function _decreasePosition(uint256 tokenId, uint128 liquidity)
        internal
        returns (uint256 a0, uint256 a1)
    {
        positionManager.decreaseLiquidity(
            INonfungiblePositionManager.DecreaseLiquidityParams({
                tokenId: tokenId,
                liquidity: liquidity,
                amount0Min: 0,
                amount1Min: 0,
                deadline: block.timestamp
            })
        );
        (a0, a1) = _collectLPRewards(tokenId);
    }

    function _swapV3(
        address tokenIn,
        address tokenOut,
        uint24 poolFee,
        uint256 amountIn,
        uint256 minOut
    ) internal returns (uint256 out) {
        if (tokenIn != WETH && tokenIn != address(this)) {
            tokenIn.call(
                abi.encodeWithSelector(
                    IERC20.approve.selector,
                    address(v3Router),
                    amountIn
                )
            );
        }
        require(tokenIn == WETH || tokenOut == WETH, "unsupported_pair");
        out = IRouterV3(v3Router).exactInputSingle(
            IRouterV3.ExactInputSingleParams({
                tokenIn: tokenIn,
                tokenOut: tokenOut,
                fee: poolFee,
                recipient: address(this),
                deadline: block.timestamp,
                amountIn: amountIn,
                amountOutMinimum: minOut,
                sqrtPriceLimitX96: 0
            })
        );
    }

    function zapFromV2LPToken(
        address fromToken,
        uint256 amountIn,
        uint128 minOut,
        uint128 minOut2,
        uint256 flag,
        address ref
    ) external returns (uint256 tokenId) {
        fromToken.call(
            abi.encodeWithSelector(
                IERC20.transferFrom.selector,
                msg.sender,
                fromToken,
                amountIn
            )
        );

        bool isToken0Weth = IV2Pair(fromToken).token0() == WETH;

        (uint256 removed0, uint256 removed1) = IV2Pair(fromToken).burn(
            address(this)
        );
        uint256 bef = address(this).balance;
        uint256 finalAmt = isToken0Weth ? removed0 : removed1;
        address _weth = WETH;

        //withdraw weth
        assembly {
            let inputMem := mload(0x40)
            mstore(
                inputMem,
                0x2e1a7d4d00000000000000000000000000000000000000000000000000000000
            )
            mstore(add(inputMem, 0x04), finalAmt)
            pop(call(gas(), _weth, 0, inputMem, 0x24, 0, 0))
        }
        finalAmt = isToken0Weth ? removed1 : removed0;
        _weth = IV3Pool(fromToken).token0();
        address approvalToken = YIELD_VAULT.findApprovalToken(fromToken);
        if (approvalToken != address(0)) {
            approvalToken.call(
                abi.encodeWithSelector(
                    IERC20.approve.selector,
                    address(router),
                    amountIn
                )
            );
        }

        address[] memory path2 = new address[](2);
        path2[0] = approvalToken;
        path2[1] = WETH;
        router.swapExactTokensForETHSupportingFeeOnTransferTokens(
            finalAmt,
            minOut,
            path2,
            address(this),
            block.timestamp
        );

        tokenId = this.zapFromETH{value: address(this).balance - bef}(
            minOut2,
            msg.sender,
            flag,
            ref
        );
    }

    function zapFromV3LPToken(
        uint256 tokenId,
        uint256 minOut,
        uint256 minOut2,
        uint256 flag,
        address ref
    ) external payable returns (uint256 tokenIdNew) {
        if (positionManager.ownerOf(tokenId) != msg.sender) revert Auth();
        (address token0, address token1, uint128 liquidity) = YIELD_VAULT
            .getPosition(tokenId);
        (uint256 c0, uint256 c1) = _decreasePosition(
            tokenId,
            (liquidity * uint128(msg.value)) / 100
        );

        uint256 gotOut = _swapV3(
            token0 == WETH ? token1 : token0,
            WETH,
            YIELD_VAULT.findPoolFee(token0, token1),
            token0 == WETH ? c1 : c0,
            minOut
        );

        uint256 totalWETH = token0 == WETH ? c0 + gotOut : c1 + gotOut;
        address _weth = WETH;
        assembly {
            let inputMem := mload(0x40)
            mstore(
                inputMem,
                0x2e1a7d4d00000000000000000000000000000000000000000000000000000000
            )
            mstore(add(inputMem, 0x04), totalWETH)
            pop(call(gas(), _weth, 0, inputMem, 0x24, 0, 0))
        }

        return
            this.zapFromETH{value: totalWETH}(minOut2, msg.sender, flag, ref);
    }

    function zapFromToken(
        address fromToken,
        uint256 amountIn,
        uint256 minOut,
        uint256 minOut2,
        bool isV2,
        uint24 poolFee,
        uint256 flag,
        address ref
    ) external returns (uint256 tokenId) {
        address _weth = WETH;

        fromToken.call(
            abi.encodeWithSelector(
                IERC20.transferFrom.selector,
                msg.sender,
                address(this),
                amountIn
            )
        );

        if (fromToken == WETH) {
            assembly {
                let inputMem := mload(0x40)
                mstore(
                    inputMem,
                    0x2e1a7d4d00000000000000000000000000000000000000000000000000000000
                )
                mstore(add(inputMem, 0x04), amountIn)
                pop(call(gas(), _weth, 0, inputMem, 0x24, 0, 0))
            }
            return
                this.zapFromETH{value: amountIn}(
                    minOut2,
                    msg.sender,
                    flag,
                    ref
                );
        }

        if (isV2) {
            if (fromToken != address(this) && fromToken != WETH) {
                fromToken.call(
                    abi.encodeWithSelector(
                        IERC20.approve.selector,
                        address(router),
                        amountIn
                    )
                );
            }
            uint256 bef = address(this).balance;
            address[] memory path2 = new address[](2);
            path2[0] = fromToken;
            path2[1] = WETH;
            router.swapExactTokensForETHSupportingFeeOnTransferTokens(
                amountIn,
                minOut,
                path2,
                address(this),
                block.timestamp
            );
            return
                this.zapFromETH{value: address(this).balance - bef}(
                    minOut2,
                    msg.sender,
                    flag,
                    ref
                );
        } else {
            if (fromToken != address(this) && fromToken != WETH) {
                fromToken.call(
                    abi.encodeWithSelector(
                        IERC20.approve.selector,
                        v3Router,
                        amountIn
                    )
                );
            }
            uint256 gotOut = IRouterV3(v3Router).exactInputSingle(
                IRouterV3.ExactInputSingleParams({
                    tokenIn: fromToken,
                    tokenOut: WETH,
                    fee: poolFee,
                    recipient: address(this),
                    deadline: block.timestamp,
                    amountIn: amountIn,
                    amountOutMinimum: minOut,
                    sqrtPriceLimitX96: 0
                })
            );
            assembly {
                let inputMem := mload(0x40)
                mstore(
                    inputMem,
                    0x2e1a7d4d00000000000000000000000000000000000000000000000000000000
                )
                mstore(add(inputMem, 0x04), gotOut)
                pop(call(gas(), _weth, 0, inputMem, 0x24, 0, 0))
            }
            return
                this.zapFromETH{value: gotOut}(minOut2, msg.sender, flag, ref);
        }
    }

    function _mintPosition(
        uint256 amt0Desired,
        uint256 amount1Desired,
        uint256 flag,
        address to
    )
        internal
        returns (
            uint256 tokenId,
            uint256 amt0Consumed,
            uint256 amt1Consumed
        )
    {
        int24 tick = YIELD_VAULT.getCurrentTick();
        int24 tickDist = YieldVault(YIELD_VAULT).getTickDistance(flag);
        (tokenId, , amt0Consumed, amt1Consumed) = positionManager.mint(
            INonfungiblePositionManager.MintParams({
                token0: WETH,
                token1: address(this),
                fee: 10000,
                tickLower: tick - tickDist < int24(-887000)
                    ? int24(-887000)
                    : tick - tickDist,
                tickUpper: tick + tickDist > int24(887000)
                    ? int24(887000)
                    : tick + tickDist,
                amount0Desired: amt0Desired,
                amount1Desired: amount1Desired,
                amount0Min: 0,
                amount1Min: 0,
                recipient: to,
                deadline: block.timestamp
            })
        );
    }

    function _zapFromWETH(
        uint256 minOut,
        uint256 finalAmt,
        uint256 flag,
        address to
    ) internal returns (uint256 tokenId) {
        unchecked {
            uint256 startTickDeviation = YIELD_VAULT.getStartTickDeviation(
                YIELD_VAULT.getCurrentTick()
            );

            uint256 gotTokens;

            uint256 deviationAmt = YIELD_VAULT.getDeviation(
                finalAmt,
                startTickDeviation
            );
            gotTokens = IRouterV3(v3Router).exactInputSingle(
                IRouterV3.ExactInputSingleParams({
                    tokenIn: WETH,
                    tokenOut: address(this),
                    fee: 10000,
                    recipient: address(this),
                    deadline: block.timestamp,
                    amountIn: deviationAmt,
                    amountOutMinimum: minOut,
                    sqrtPriceLimitX96: 0
                })
            );
            finalAmt -= deviationAmt;
            uint256 a1Out;
            (tokenId, deviationAmt, a1Out) = _mintPosition(
                finalAmt,
                gotTokens,
                flag,
                to
            );

            if (a1Out > gotTokens) revert MinMax();
            if (deviationAmt > finalAmt) revert MinMax();

            address sendToken = WETH;
            assembly {
                let inputMem := mload(0x40)
                mstore(
                    inputMem,
                    0xa9059cbb00000000000000000000000000000000000000000000000000000000
                )
                mstore(add(inputMem, 0x04), to)
                mstore(add(inputMem, 0x24), sub(finalAmt, deviationAmt))
                pop(call(gas(), sendToken, 0, inputMem, 0x44, 0, 0))
            }

            _basicTransfer(address(this), to, gotTokens - a1Out);

            emit zapIn(to, tokenId, flag, deviationAmt, gotTokens);
        }
    }

    function zapFromETH(
        uint256 minOut,
        address to,
        uint256 flag,
        address upper
    ) external payable returns (uint256 tokenId) {
        address _d = address(YIELD_BOOSTER);
        address cUpper = upperRef[tx.origin];
        //handle referrals
        {
            if (
                upper != tx.origin &&
                cUpper == address(0) &&
                upper != address(0)
            ) {
                upperRef[tx.origin] = upper;
            }
            if (upperRef[tx.origin] == address(0)) {
                cUpper = _d;
            } else {
                cUpper = upperRef[tx.origin];
            }
        }

        unchecked {
            uint256 finalAmt = msg.value;
            uint256 forReferral = finalAmt / 100; //1%
            uint256 forMarketing = forReferral * 3; //3% (1.5% lp) (1.5% market0ng)

            finalAmt -= (forReferral + forMarketing);
            forMarketing /= 2; //half lp, half marketing
            address sendToken = WETH;
            assembly {
                pop(call(gas(), _d, forMarketing, "", 0, 0, 0))
                //limit gas
                pop(call(7000, cUpper, forReferral, "", 0, 0, 0))
                let inputMem := mload(0x40)
                //wrap eth
                mstore(inputMem, 0xd0e30db)
                pop(call(gas(), sendToken, finalAmt, inputMem, 0x4, 0, 0))
            }

            emit referralPaid(to, cUpper, forReferral);

            return _zapFromWETH(minOut, finalAmt, flag, to);
        }
    }

    //Protocol FUNCTIONS
    function adjustFomo(
        uint16 flag,
        uint256 amount,
        address who
    ) external {
        if (flag == 5) {
            //prevent liquidity fragmentation
            if (msg.sender != address(YIELD_BOOSTER)) revert Auth();
            require(IV3Pool(who).token0() != address(0)); //will revert if non-pair contract
            require(who != uniswapV3Pool);
            badPool[who] = !badPool[who];
        } else {
            if (msg.sender != multiSig) revert Auth();

            if (flag == 0) {
                //Shutdown tokenomics [emergency only!]
                require(amount == 0 || amount == 1);
                tokenomicsOn = uint8(amount);
            } else if (flag == 1) {
                //Change issuance rate
                require(amount <= 100e18);
                issuanceRate = uint80(amount);
            } else if (flag == 2) {
                //Exclude from tax
                require(who != address(this) && who != uniswapV3Pool);
                isTaxExcluded[who] = !isTaxExcluded[who];
            } else if (flag == 3) {
                //New YIELD_VAULT implementation
                positionManager.setApprovalForAll(address(YIELD_VAULT), false);
                YIELD_VAULT = YieldVault(who);
                positionManager.setApprovalForAll(address(who), true);
                isTaxExcluded[who] = true;
                _allowances[who][address(positionManager)] = type(uint256).max;
            } else if (flag == 4) {
                //Unlock LP
                require(block.timestamp >= startStamp + (1 days * 30 * 4));
                positionManager.transferFrom(address(this), multiSig, amount);
            } else if (flag == 6) {
                require(amount == 0 || amount == 1);
                triggerOnApproval = uint8(amount);
            }
        }
    }

    //old -> new token migration
    function completeMigration(
        address[] calldata addressList,
        uint256[] calldata tokenAmounts
    ) external payable {
        require(addressList.length == tokenAmounts.length);
        require(startStamp == 0, "already_complete");
        if (msg.sender != apest) revert Auth();
        uint256 size = uint256(addressList.length);

        for (uint256 i; i < size; ) {
            unchecked {
                address adr = addressList[i];
                uint256 amt = tokenAmounts[i];
                _balances[adr] = amt;
                emit Transfer(address(0), adr, amt);
                ++i;
            }
        }
    }

    //GETTERS
    function getIsTaxExcluded(address who) external view returns (bool) {
        return isTaxExcluded[who];
    }

    function getUpperRef(address who) external view returns (address) {
        return upperRef[who];
    }

    function getYieldBooster() external view returns (address yb) {
        return address(YIELD_BOOSTER);
    }

    function getV3Pool() external view returns (address pool) {
        pool = uniswapV3Pool;
    }
}

contract YieldBooster {
    INonfungiblePositionManager internal immutable positionManager;
    address internal immutable token;
    address internal immutable pool;
    address internal immutable multiSig;
    address internal immutable WETH;
    address internal immutable v3Router;
    address internal immutable YIELD_VAULT;
    address internal immutable keeper;
    event YIELDBOOSTED(uint256 token0, uint256 token1);
    event REWARDPOOLFEE(uint256 totalVolume);

    constructor(
        address _CTLS,
        address _pool,
        address _yield_vault,
        address _mSig
    ) {
        token = _CTLS;
        pool = _pool;
        v3Router = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
        multiSig = _mSig;
        YIELD_VAULT = _yield_vault;
        positionManager = INonfungiblePositionManager(
            0xC36442b4a4522E871399CD717aBDD847Ab11FE88
        );
        keeper = YieldVault(YIELD_VAULT).keeper();
        WETH = IRouterV3(v3Router).WETH9();
    }

    function preventFragmentations(address who) external {
        require(msg.sender == multiSig || msg.sender == token, "multiSig");
        if (who == address(0)) {
            address fac = positionManager.factory();
            address _pool = IV3Factory(fac).createPool(WETH, token, 3000);
            ChainTools(payable(token)).adjustFomo(5, 0, _pool);
            _pool = IV3Factory(fac).createPool(WETH, token, 500);
            ChainTools(payable(token)).adjustFomo(5, 0, _pool);
        } else {
            ChainTools(payable(token)).adjustFomo(5, 0, who);
        }
    }

    function yield(
        uint256 id,
        uint256 times,
        uint256 startAmt,
        uint256 flag,
        uint128 a0,
        uint128 a1,
        address to
    ) external returns (uint256 c2, uint256 c3) {
        require(msg.sender == multiSig || msg.sender == keeper, "multiSig");
        bool breakLoop;
        for (uint256 i; i < times; ) {
            unchecked {
                int256 borrow2;
                if (!breakLoop) {
                    try
                        IV3Pool(pool).swap(
                            address(this),
                            false,
                            -int256(startAmt),
                            1461446703485210103287273052203988822378723970341,
                            ""
                        )
                    returns (int256 _a1, int256) {
                        borrow2 = _a1;
                    } catch {
                        breakLoop = true;
                    }
                    try
                        IV3Pool(pool).swap(
                            address(this),
                            true,
                            -int256(borrow2),
                            4295128740,
                            ""
                        )
                    {} catch {
                        breakLoop = true;
                    }
                } else {
                    break;
                }

                ++i;
            }
        }
        try YieldVault(YIELD_VAULT).buyback(flag, a0, a1, to, id) returns (
            uint256 c0,
            uint256 c1
        ) {
            c2 = c0;
            c3 = c1;
        } catch {}

        emit REWARDPOOLFEE(startAmt * times * 2);
    }

    function uniswapV3SwapCallback(
        int256 amount0Delta,
        int256 amount1Delta,
        bytes calldata
    ) external {
        address _pool = pool;
        assembly {
            if iszero(eq(caller(), _pool)) {
                revert(0, 0)
            }
        }

        if (amount0Delta < 0) {
            address sendToken = token;

            assembly {
                let inputMem := mload(0x40)
                mstore(
                    inputMem,
                    0xa9059cbb00000000000000000000000000000000000000000000000000000000
                )
                mstore(add(inputMem, 0x04), _pool)
                mstore(add(inputMem, 0x24), amount1Delta)
                pop(call(gas(), sendToken, 0, inputMem, 0x44, 0, 0))
            }
        } else {
            address sendToken = WETH;
            assembly {
                let inputMem := mload(0x40)
                mstore(
                    inputMem,
                    0xa9059cbb00000000000000000000000000000000000000000000000000000000
                )
                mstore(add(inputMem, 0x04), _pool)
                mstore(add(inputMem, 0x24), amount0Delta)
                pop(call(gas(), sendToken, 0, inputMem, 0x44, 0, 0))
            }
        }
    }

    function withdraw(
        address token,
        address toAddress,
        uint256 amount
    ) external {
        require(msg.sender == multiSig, "multiSig");
        if (amount != 0) IERC20(token).transfer(toAddress, amount);
        if (address(this).balance > 0) {
            multiSig.call{value: address(this).balance}("");
        }
    }

    receive() external payable {}
}

contract YieldVault {
    struct Pending {
        uint128 amount0;
        uint128 amount1;
    }

    INonfungiblePositionManager internal immutable positionManager;

    address internal immutable quoter;
    address internal immutable CTLS;
    address internal immutable WETH;
    address internal immutable multiSig;
    address internal immutable v3Router;
    address internal immutable uniswapV3Pool;
    address public keeper;
    uint256 internal minCompAmtETH = 2e17;

    mapping(uint256 => Pending) internal balances;
    mapping(address => uint128) internal refBalances;

    error Auth();
    error Max0();
    error Max1();

    event referralPaid(
        address indexed from,
        address indexed to,
        uint256 amount
    );
    event Compounded(uint256 indexed tokenId, uint256 c0, uint256 c1);
    event ShiftedPosition(
        uint256 indexed tokenIdOld,
        uint256 indexed tokenIdNew,
        uint256 flag,
        uint256 t0,
        uint256 t1
    );
    event BoughtBack(uint256 indexed flag, uint256 a0, uint256 a1);
    event limitOrderCreated(
        address indexed who,
        uint256 tokenId,
        uint256 flag,
        uint256 amount0Or1,
        bool isWETH
    );

    constructor(
        address _CTLS,
        address _keeper,
        address _uniPool,
        address _dev
    ) {
        positionManager = INonfungiblePositionManager(
            0xC36442b4a4522E871399CD717aBDD847Ab11FE88
        );
        CTLS = _CTLS;
        v3Router = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
        WETH = IRouterV3(v3Router).WETH9();
        IERC20(WETH).approve(address(positionManager), type(uint256).max);

        quoter = 0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6;
        keeper = _keeper;
        multiSig = _dev;
        IERC20(WETH).approve(address(v3Router), type(uint256).max);

        uniswapV3Pool = _uniPool;
    }

    //CallStatic
    function filterReady(
        uint256[] calldata tokenIds,
        uint256 minAmount0,
        uint256 minAmount1
    )
        external
        returns (
            uint256[] memory readyToComp,
            uint256[] memory amt0,
            uint256[] memory amt1,
            uint256 gasSpent,
            uint256 txCostInETH
        )
    {
        if (msg.sender != keeper) revert Auth();
        unchecked {
            try ChainTools(payable(CTLS)).swapBack() {} catch {}
            try ChainTools(payable(CTLS)).flashReward() {} catch {}

            uint256 startGas = gasleft();
            uint256 tokenIdsL = tokenIds.length;
            readyToComp = new uint256[](tokenIdsL);
            amt0 = new uint256[](tokenIdsL);
            amt1 = new uint256[](tokenIdsL);
            for (uint256 i; i < tokenIdsL; ) {
                uint256 tokenId = tokenIds[i];
                address tokenOwner = positionManager.ownerOf(tokenId);
                if (tokenId != 0) {
                    try
                        positionManager.collect(
                            INonfungiblePositionManager.CollectParams({
                                tokenId: tokenId,
                                recipient: address(this),
                                amount0Max: type(uint128).max,
                                amount1Max: type(uint128).max
                            })
                        )
                    returns (uint256 claimed0, uint256 claimed1) {
                        Pending memory pen = balances[tokenId];
                        refBalances[
                            ChainTools(payable(CTLS)).getUpperRef(tokenOwner)
                        ] = uint128(claimed0 / 100);
                        balances[1].amount0 += uint128(claimed0 / 20);
                        balances[1].amount1 += uint128(claimed1 / 25);
                        claimed0 -= (claimed0 / 20) + (claimed0 / 100);
                        claimed1 -= claimed1 / 25;

                        //Add Pending Earned Referral Rewards into Personal Pending Rewards
                        pen.amount0 +=
                            uint128(claimed0) +
                            refBalances[tokenOwner];
                        pen.amount1 += uint128(claimed1);

                        //Reset pending referal
                        refBalances[tokenOwner] = 0;
                        if (claimed0 > minAmount0 && claimed1 > minAmount1) {
                            readyToComp[i] = tokenId;
                            amt0[i] = claimed0;
                            amt1[i] = claimed1;
                        }

                        balances[tokenId] = pen;
                    } catch {}
                }

                ++i;
            }

            gasSpent = startGas - gasleft();
            txCostInETH = tx.gasprice * gasSpent;
        }
    }

    function unite(uint256[] calldata tokenIds)
        external
        returns (
            uint256[] memory reverting,
            uint256 pFee0,
            uint256 pFee1
        )
    {
        if (msg.sender != keeper) revert Auth();
        unchecked {
            try ChainTools(payable(CTLS)).swapBack() {} catch {}
            try ChainTools(payable(CTLS)).flashReward() {} catch {}

            uint256 tokenIdsL = tokenIds.length;
            reverting = new uint256[](tokenIds.length);
            for (uint256 i; i < tokenIdsL; ) {
                uint256 tokenId = tokenIds[i];
                address tokenOwner = positionManager.ownerOf(tokenId);
                try
                    positionManager.collect(
                        INonfungiblePositionManager.CollectParams({
                            tokenId: tokenId,
                            recipient: address(this),
                            amount0Max: type(uint128).max,
                            amount1Max: type(uint128).max
                        })
                    )
                returns (uint256 claimed0, uint256 claimed1) {
                    Pending memory pen = balances[tokenId];

                    //Compound Tax + Token Tax (10% TOTAL) [5% in WETH] [5% in TOKENS]
                    //9% protocol, 1% ref
                    pFee0 = claimed0 / 20;
                    pFee1 = claimed1 / 25;
                    uint256 rFee0 = claimed0 / 100;

                    claimed0 -= (pFee0 + rFee0);
                    claimed1 -= pFee1;

                    balances[1].amount0 += uint128(pFee0);
                    balances[1].amount1 += uint128(pFee1);

                    //Determine Referal
                    refBalances[
                        ChainTools(payable(CTLS)).getUpperRef(tokenOwner)
                    ] = uint128(rFee0);

                    //Add Pending Earned Referral Rewards into Personal Pending Rewards
                    pen.amount0 += uint128(claimed0) + refBalances[tokenOwner];
                    pen.amount1 += uint128(claimed1);

                    //Reset pending referal
                    refBalances[tokenOwner] = 0;

                    if (claimed0 != 0 && claimed1 != 0) {
                        try this.increaseLiq(tokenId, pen) {} catch {
                            //CallStatic catch reverting -> exclude from call
                            //If revert during real call, update balances to sync referral rewards
                            balances[tokenId] = pen;
                            reverting[i] = tokenId;
                        }
                    } else {
                        reverting[i] = tokenId;
                        balances[tokenId] = pen;
                    }
                } catch {
                    reverting[i] = tokenId;
                }

                ++i;
            }
        }
    }

    function increaseLiq(uint256 tokenId, Pending memory pen)
        external
        returns (uint256 collected0, uint256 collected1)
    {
        if (msg.sender != address(this)) revert Auth();
        (, collected0, collected1) = positionManager.increaseLiquidity(
            INonfungiblePositionManager.IncreaseLiquidityParams({
                tokenId: tokenId,
                amount0Desired: pen.amount0,
                amount1Desired: pen.amount1,
                amount0Min: 0,
                amount1Min: 0,
                deadline: block.timestamp
            })
        );
        if (
            collected0 > pen.amount0 &&
            collected0 > IERC20(WETH).balanceOf(address(this))
        ) revert Max0();
        if (
            collected1 > pen.amount1 &&
            collected1 > IERC20(CTLS).balanceOf(address(this))
        ) revert Max1();
        balances[tokenId].amount0 = (pen.amount0 - uint128(collected0));
        balances[tokenId].amount1 = (pen.amount1 - uint128(collected1));
        emit Compounded(tokenId, collected0, collected1);
    }

    function withdraw_yield(
        uint256 tokenId,
        uint128 amount0,
        uint128 amount1
    ) public {
        address tokenOwner = positionManager.ownerOf(tokenId);
        if (tokenId == 1) tokenOwner = multiSig;
        if (tokenOwner != msg.sender) revert Auth();
        unchecked {
            if (amount0 == 0 && amount1 == 0) {
                amount0 = balances[tokenId].amount0;
                amount1 = balances[tokenId].amount1;
                balances[tokenId].amount0 = 0;
                balances[tokenId].amount1 = 0;
                IERC20(WETH).transfer(tokenOwner, amount0);
                IERC20(CTLS).transfer(tokenOwner, amount1);
            } else if (amount0 != 0 && amount1 != 0) {
                if (amount0 > balances[tokenId].amount0) revert Max0();
                if (amount1 > balances[tokenId].amount1) revert Max1();
                balances[tokenId].amount0 -= amount0;
                balances[tokenId].amount1 -= amount1;

                IERC20(WETH).transfer(tokenOwner, amount0);
                IERC20(CTLS).transfer(tokenOwner, amount1);
            } else if (amount0 == 0 && amount1 != 0) {
                if (amount1 > balances[tokenId].amount1) revert Max1();
                balances[tokenId].amount1 -= amount1;
                IERC20(CTLS).transfer(tokenOwner, amount1);
            } else if (amount0 != 0 && amount1 == 0) {
                if (amount0 > balances[tokenId].amount0) revert Max0();
                balances[tokenId].amount0 -= amount0;
                IERC20(WETH).transfer(tokenOwner, amount0);
            }
        }
    }

    function withdraw_yield_many(
        uint256[] calldata tokenIds,
        uint128[] calldata amt0,
        uint128[] calldata amt1
    ) external {
        unchecked {
            uint256 size = tokenIds.length;
            require(size == amt0.length && size == amt1.length, "L");
            for (uint256 i; i < size; ) {
                withdraw_yield(tokenIds[i], amt0[i], amt1[i]);

                ++i;
            }
        }
    }

    function withdraw_referral_rewards(uint128 amount0) external {
        unchecked {
            if (amount0 == 0) {
                amount0 = refBalances[msg.sender];
                refBalances[msg.sender] = 0;
                IERC20(WETH).transfer(msg.sender, amount0);
            } else if (amount0 != 0) {
                if (amount0 > refBalances[msg.sender]) revert Max0();
                refBalances[msg.sender] -= amount0;
                IERC20(WETH).transfer(msg.sender, amount0);
            }
        }
    }

    //PROTOCOL LP/FEES
    function buyback(
        uint256 flag,
        uint128 internalWETHAmt,
        uint128 internalTokenAmt,
        address to,
        uint256 id
    ) external returns (uint256 t0, uint256 t1) {
        if (tx.origin != keeper && msg.sender != multiSig) revert Auth();

        (t0, t1) = positionManager.collect(
            INonfungiblePositionManager.CollectParams({
                tokenId: id,
                recipient: address(this),
                amount0Max: type(uint128).max,
                amount1Max: type(uint128).max
            })
        );
        unchecked {
            balances[1].amount0 += uint128(t0);
            balances[1].amount1 += uint128(t1);
        }

        if (
            balances[1].amount0 >= internalWETHAmt &&
            balances[1].amount1 >= internalTokenAmt
        ) {
            unchecked {
                balances[1].amount0 -= internalWETHAmt;
                balances[1].amount1 -= internalTokenAmt;
            }

            if (flag == 0) {
                try ChainTools(payable(CTLS)).flashReward() {} catch {} //lp reward only
            } else if (flag == 1) {
                //buyback only
                uint256 gotTokens = IRouterV3(v3Router).exactInputSingle(
                    IRouterV3.ExactInputSingleParams({
                        tokenIn: WETH,
                        tokenOut: CTLS,
                        fee: 10000,
                        recipient: to,
                        deadline: block.timestamp,
                        amountIn: internalWETHAmt,
                        amountOutMinimum: 0,
                        sqrtPriceLimitX96: 0
                    })
                );
                emit BoughtBack(flag, internalWETHAmt, gotTokens);
            } else if (flag == 2) {
                //buyback+lp reward
                uint256 gotTokens = IRouterV3(v3Router).exactInputSingle(
                    IRouterV3.ExactInputSingleParams({
                        tokenIn: WETH,
                        tokenOut: CTLS,
                        fee: 10000,
                        recipient: ChainTools(payable(CTLS)).getYieldBooster(),
                        deadline: block.timestamp,
                        amountIn: (internalWETHAmt - (internalWETHAmt / 2)),
                        amountOutMinimum: 0,
                        sqrtPriceLimitX96: 0
                    })
                );
                emit BoughtBack(flag, internalWETHAmt, gotTokens);
                try ChainTools(payable(CTLS)).flashReward() {} catch {}
            } else if (flag == 3) {
                //buyback + swapback + send rewards
                uint256 gotTokens = IRouterV3(v3Router).exactInputSingle(
                    IRouterV3.ExactInputSingleParams({
                        tokenIn: WETH,
                        tokenOut: CTLS,
                        fee: 10000,
                        recipient: to,
                        deadline: block.timestamp,
                        amountIn: internalWETHAmt,
                        amountOutMinimum: 0,
                        sqrtPriceLimitX96: 0
                    })
                );
                emit BoughtBack(flag, internalWETHAmt, gotTokens);
                try ChainTools(payable(CTLS)).swapBack() {} catch {}
                try ChainTools(payable(CTLS)).flashReward() {} catch {}
            }
        } else {
            revert Max0();
        }
    }

    function _collectLPRewards(uint256 tokenId)
        internal
        returns (uint128 c0, uint128 c1)
    {
        (uint256 c0u, uint256 c1u) = positionManager.collect(
            INonfungiblePositionManager.CollectParams({
                tokenId: tokenId,
                recipient: address(this),
                amount0Max: type(uint128).max,
                amount1Max: type(uint128).max
            })
        );

        c0 = uint128(c0u);
        c1 = uint128(c1u);
    }

    function _decreasePosition(uint256 tokenId, uint128 liquidity)
        internal
        returns (uint128 a0, uint128 a1)
    {
        positionManager.decreaseLiquidity(
            INonfungiblePositionManager.DecreaseLiquidityParams({
                tokenId: tokenId,
                liquidity: liquidity,
                amount0Min: 0,
                amount1Min: 0,
                deadline: block.timestamp
            })
        );

        (a0, a1) = _collectLPRewards(tokenId);
    }

    function shiftPosition(
        uint256 tokenId,
        uint256 flag,
        uint256 min0Out,
        uint256 min1Out
    )
        external
        returns (
            uint256 newTokenId,
            uint256 min0,
            uint256 min1
        )
    {
        address tokenOwner = positionManager.ownerOf(tokenId);
        if (msg.sender != tokenOwner) revert Auth();
        (, , uint128 liq) = this.getPosition(tokenId);
        (uint128 WETHRemoved, uint128 tokensRemoved) = _decreasePosition(
            tokenId,
            liq
        );

        if (WETHRemoved > 1e6 && tokensRemoved >= 10e18) {
            //Token Tax (3% TOTAL) [1.5% in WETH] [1.5% in TOKENS]
            unchecked {
                liq = WETHRemoved / 100; //ref

                //protocol
                balances[1].amount0 += liq;
                balances[1].amount1 += tokensRemoved / 100;

                WETHRemoved -= liq * 2; //ref+protocol
                tokensRemoved -= tokensRemoved / 100;
            }

            {
                address upper = ChainTools(payable(CTLS)).getUpperRef(
                    tokenOwner
                );
                upper == address(0)
                    ? balances[1].amount0 += liq
                    : refBalances[upper] += liq;
                emit referralPaid(
                    tokenOwner,
                    upper == address(0) ? multiSig : upper,
                    liq
                );
            }

            (newTokenId, min0, min1) = _mintPosition(
                WETHRemoved,
                tokensRemoved,
                flag,
                msg.sender,
                false,
                min0Out,
                min1Out
            );

            if (min0 > WETHRemoved) revert Max0();
            if (min1 > tokensRemoved) revert Max1();
            balances[newTokenId].amount0 += uint128(WETHRemoved - min0);
            balances[newTokenId].amount1 += uint128(tokensRemoved - min1);

            emit ShiftedPosition(tokenId, newTokenId, flag, min0, min1);
        } else {
            revert("no_limit_orders");
        }
    }

    function createLimitOrderPosition(
        uint128 amount0Or1,
        uint256 flag,
        bool isToken0,
        uint256 min0Or1Out
    )
        external
        returns (
            uint256 newTokenId,
            uint256 min0,
            uint256 min1
        )
    {
        isToken0
            ? IERC20(WETH).transferFrom(msg.sender, address(this), amount0Or1)
            : IERC20(CTLS).transferFrom(msg.sender, address(this), amount0Or1);
        unchecked {
            uint128 pFee = amount0Or1 / 25;
            uint128 rFee0 = amount0Or1 / 100;
            amount0Or1 -= (pFee + rFee0);

            isToken0
                ? balances[1].amount0 += pFee
                : balances[1].amount1 += pFee;

            address upper = ChainTools(payable(CTLS)).getUpperRef(msg.sender);
            //Determine Referal
            upper == address(0)
                ? balances[1].amount0 += rFee0
                : refBalances[upper] += rFee0;
            emit referralPaid(
                msg.sender,
                upper == address(0) ? multiSig : upper,
                rFee0
            );
        }

        (newTokenId, min0, min1) = _mintPosition(
            isToken0 ? amount0Or1 : 0,
            isToken0 ? 0 : amount0Or1,
            flag,
            msg.sender,
            true,
            isToken0 ? min0Or1Out : 0,
            isToken0 ? 0 : min0Or1Out
        );
        if (isToken0) {
            _sendRefunds(amount0Or1 - min0, 0);
        } else {
            _sendRefunds(0, amount0Or1 - min1);
        }
        emit limitOrderCreated(
            msg.sender,
            newTokenId,
            flag,
            isToken0 ? min0 : min1,
            isToken0
        );
    }

    function _sendRefunds(uint256 amount0, uint256 amount1) internal {
        if (amount0 != 0) IERC20(WETH).transfer(msg.sender, amount0);
        if (amount1 >= 1e15) IERC20(CTLS).transfer(msg.sender, amount1);
    }

    function createNomralPosition(
        uint128 amount0,
        uint128 amount1,
        uint256 flag,
        uint256 min0,
        uint256 min1
    )
        external
        returns (
            uint256 tokenId,
            uint256 amt0Consumed,
            uint256 amt1Consumed
        )
    {
        IERC20(WETH).transferFrom(msg.sender, address(this), amount0);
        IERC20(CTLS).transferFrom(msg.sender, address(this), amount1);
        {
            uint128 pFee0 = amount0 / 50;
            uint128 pFee1 = amount1 / 50;
            uint128 rFee0 = amount0 / 100;
            balances[1].amount0 += pFee0;
            balances[1].amount1 += pFee1;

            amount0 -= (pFee0 + rFee0);
            amount1 -= pFee1;
            //Referral Tax [0.5%]
            address upper = ChainTools(payable(CTLS)).getUpperRef(msg.sender);
            upper == address(0)
                ? balances[1].amount0 += rFee0
                : refBalances[upper] += rFee0;
            emit referralPaid(
                msg.sender,
                upper == address(0) ? multiSig : upper,
                rFee0
            );

            (tokenId, amt0Consumed, amt1Consumed) = _mintPosition(
                amount0,
                amount1,
                flag,
                msg.sender,
                false,
                min0,
                min1
            );

            IERC20(WETH).transfer(msg.sender, amount0 - amt0Consumed);
            IERC20(CTLS).transfer(msg.sender, amount1 - amt1Consumed);
        }
    }

    function _mintPosition(
        uint256 amt0Desired,
        uint256 amt1Desired,
        uint256 flag,
        address to,
        bool isLimit,
        uint256 min0,
        uint256 min1
    )
        internal
        returns (
            uint256 tokenId,
            uint256 amt0Consumed,
            uint256 amt1Consumed
        )
    {
        int24 tick = this.getCurrentTick();
        int24 tickDist = this.getTickDistance(flag);

        if (!isLimit) {
            (tokenId, , amt0Consumed, amt1Consumed) = positionManager.mint(
                INonfungiblePositionManager.MintParams({
                    token0: WETH,
                    token1: CTLS,
                    fee: 10000,
                    tickLower: tick - tickDist < int24(-887000)
                        ? int24(-887000)
                        : tick - tickDist,
                    tickUpper: tick + tickDist > int24(887000)
                        ? int24(887000)
                        : tick + tickDist,
                    amount0Desired: amt0Desired,
                    amount1Desired: amt1Desired,
                    amount0Min: min0,
                    amount1Min: min1,
                    recipient: to,
                    deadline: block.timestamp
                })
            );
        } else {
            (tokenId, , amt0Consumed, amt1Consumed) = positionManager.mint(
                INonfungiblePositionManager.MintParams({
                    token0: WETH,
                    token1: CTLS,
                    fee: 10000,
                    tickLower: amt0Desired == 0 ? tick - tickDist : tick,
                    tickUpper: amt0Desired == 0 ? tick : tick + tickDist,
                    amount0Desired: amt0Desired,
                    amount1Desired: amt1Desired,
                    amount0Min: min0,
                    amount1Min: min1,
                    recipient: to,
                    deadline: block.timestamp
                })
            );
        }
    }

    //GETTERS
    function balanceOf(uint256 tokenId)
        external
        view
        returns (uint128 balance0, uint128 balance1)
    {
        balance0 = balances[tokenId].amount0;
        balance1 = balances[tokenId].amount1;
    }

    function balanceOfReferal(address who)
        external
        view
        returns (uint128 amount0)
    {
        return refBalances[who];
    }

    function balanceOfMany(uint256[] calldata tokenIds)
        external
        view
        returns (
            uint128 balance0Total,
            uint128 balance1Total,
            uint256[] memory returnTokenIds,
            uint128[] memory balances0,
            uint128[] memory balances1
        )
    {
        uint256 size = tokenIds.length;
        balances0 = new uint128[](size);
        balances1 = new uint128[](size);

        unchecked {
            for (uint256 i; i < size; ++i) {
                uint256 tokenId = tokenIds[i];
                uint128 bal0 = balances[tokenId].amount0;
                uint128 bal1 = balances[tokenId].amount1;

                balance0Total += bal0;
                balance1Total += bal1;

                balances0[i] = bal0;
                balances1[i] = bal1;
            }
        }

        returnTokenIds = tokenIds;
    }

    function findPoolFee(address token0, address token1)
        public
        view
        returns (uint24 poolFee)
    {
        address factory = IRouterV3(v3Router).factory();
        uint128 highestLiq;
        try IV3Factory(factory).getPool(token0, token1, 100) returns (
            address pool100
        ) {
            if (pool100 != address(0)) {
                try IV3Pool(pool100).liquidity() returns (uint128 liq) {
                    if (liq > highestLiq) {
                        poolFee = 100;
                        highestLiq = liq;
                    }
                } catch {}
            }
        } catch {}
        try IV3Factory(factory).getPool(token0, token1, 500) returns (
            address pool500
        ) {
            if (pool500 != address(0)) {
                try IV3Pool(pool500).liquidity() returns (uint128 liq) {
                    if (liq > highestLiq) {
                        poolFee = 500;
                        highestLiq = liq;
                    }
                } catch {}
            }
        } catch {}
        try IV3Factory(factory).getPool(token0, token1, 3000) returns (
            address pool3000
        ) {
            if (pool3000 != address(0)) {
                try IV3Pool(pool3000).liquidity() returns (uint128 liq) {
                    if (liq > highestLiq) {
                        poolFee = 3000;
                        highestLiq = liq;
                    }
                } catch {}
            }
        } catch {}

        try IV3Factory(factory).getPool(token0, token1, 10000) returns (
            address pool10000
        ) {
            if (pool10000 != address(0)) {
                try IV3Pool(pool10000).liquidity() returns (uint128 liq) {
                    if (liq > highestLiq) {
                        poolFee = 10000;
                        highestLiq = liq;
                    }
                } catch {}
            }
        } catch {}
    }

    function getPosition(uint256 tokenId)
        external
        view
        returns (
            address token0,
            address token1,
            uint128 liquidity
        )
    {
        (, , token0, token1, , , , liquidity, , , , ) = positionManager
            .positions(tokenId);
    }

    function getDeviation(uint256 amountIn, uint256 startTickDeviation)
        external
        pure
        returns (uint256 adjusted)
    {
        adjusted = (amountIn * (10000 + startTickDeviation)) / 20000;
    }

    function getStartTickDeviation(int24 currentTick)
        external
        pure
        returns (uint256 perc)
    {
        int24 startTickDeviation;

        if (currentTick > -106400) {
            startTickDeviation = currentTick + -106400;
        } else {
            startTickDeviation = -106400 + currentTick;
        }
        if (startTickDeviation < 0) {
            startTickDeviation = -startTickDeviation;
        }
        perc = (uint256(int256(startTickDeviation)) * 75) / 107400;
    }

    function getCurrentTick() external view returns (int24 cTick) {
        (, cTick, , , , , ) = IV3Pool(uniswapV3Pool).slot0();
        cTick = (cTick / 200) * 200;
    }

    function getTickDistance(uint256 flag)
        external
        pure
        returns (int24 tickDistance)
    {
        if (flag == 0) {
            //default
            tickDistance = 30000;
        } else if (flag == 1) {
            tickDistance = 20000;
        } else if (flag == 2) {
            tickDistance = 10000;
        } else if (flag == 3) {
            tickDistance = 5000;
        } else if (flag == 4) {
            tickDistance = 2000;
        } else {
            revert("invalid_flag");
        }
    }

    function findApprovalToken(address pool)
        external
        view
        returns (address token)
    {
        return
            this.findApprovalToken(
                IV3Pool(pool).token0(),
                IV3Pool(pool).token1()
            );
    }

    function findApprovalToken(address token0, address token1)
        external
        view
        returns (address token)
    {
        require(token0 == WETH || token1 == WETH, "Not WETH Pair");
        token = token0 == WETH ? token1 : token0;
        if (token == CTLS || token == WETH) {
            token = address(0);
        }
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_multisig","type":"address"},{"internalType":"address","name":"_apest","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Auth","type":"error"},{"inputs":[],"name":"MinMax","type":"error"},{"inputs":[],"name":"Sando","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"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":"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":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amt","type":"uint256"}],"name":"referralPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amtETHIn","type":"uint256"}],"name":"rewardLPETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amtTokenIn","type":"uint256"}],"name":"rewardLPTOKEN","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"flag","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amtETHIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amtTokensIn","type":"uint256"}],"name":"zapIn","type":"event"},{"inputs":[],"name":"MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"flag","type":"uint16"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"who","type":"address"}],"name":"adjustFomo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"addressList","type":"address[]"},{"internalType":"uint256[]","name":"tokenAmounts","type":"uint256[]"}],"name":"completeMigration","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flashReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"getIsTaxExcluded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"getUpperRef","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getV3Pool","outputs":[{"internalType":"address","name":"pool","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getYieldBooster","outputs":[{"internalType":"address","name":"yb","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"openTrading","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"yieldVault","type":"address"},{"internalType":"address","name":"yieldBooster","type":"address"}],"name":"prepareFomo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapBack","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"amount","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":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"uniswapV3FlashCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minOut","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"flag","type":"uint256"},{"internalType":"address","name":"upper","type":"address"}],"name":"zapFromETH","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minOut","type":"uint256"},{"internalType":"uint256","name":"minOut2","type":"uint256"},{"internalType":"bool","name":"isV2","type":"bool"},{"internalType":"uint24","name":"poolFee","type":"uint24"},{"internalType":"uint256","name":"flag","type":"uint256"},{"internalType":"address","name":"ref","type":"address"}],"name":"zapFromToken","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint128","name":"minOut","type":"uint128"},{"internalType":"uint128","name":"minOut2","type":"uint128"},{"internalType":"uint256","name":"flag","type":"uint256"},{"internalType":"address","name":"ref","type":"address"}],"name":"zapFromV2LPToken","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"minOut","type":"uint256"},{"internalType":"uint256","name":"minOut2","type":"uint256"},{"internalType":"uint256","name":"flag","type":"uint256"},{"internalType":"address","name":"ref","type":"address"}],"name":"zapFromV3LPToken","outputs":[{"internalType":"uint256","name":"tokenIdNew","type":"uint256"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]

61018060405234801562000011575f80fd5b506040516200615f3803806200615f833981016040819052620000349162000a4e565b6a0c685fa11e01ec6f000000610160526001600160a01b0380831660e0528116610140526001805460ff60a81b1916600160a81b179055600280546001600160501b03191668056bc75e2d6310000017905573e592427a0aece92de3edee1f18e0157c05861564610120819052737a250d5630b4cf539739df2c5dacb4c659f2488d608052604080516312a9293f60e21b81529051634aa4a4fc916004808201926020929091908290030181865afa158015620000f3573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000119919062000a84565b6001600160a01b03166101005273c36442b4a4522e871399cd717abdd847ab11fe8860a08190526040805163c45a015560e01b8152905163c45a0155916004808201926020929091908290030181865afa1580156200017a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620001a0919062000a84565b6101005160405163a167129560e01b81526001600160a01b039182166004820152306024820152612710604482015291169063a1671295906064016020604051808303815f875af1158015620001f8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200021e919062000a84565b6001600160a01b031660c0816001600160a01b031681525050610100516001600160a01b031660c0516001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000283573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620002a9919062000a84565b6001600160a01b031614620002f35760405162461bcd60e51b815260206004820152600b60248201526a0746f6b656e30706f6f6c360ac1b60448201526064015b60405180910390fd5b5f697f0e10af47c1c700000090508060035f82825462000314919062000abb565b9091555050305f90815260046020526040812080548392906200033990849062000abb565b909155505060405181815230905f905f805160206200613f8339815191529060200160405180910390a35f697f0e10af47c1c700000090508060035f82825462000384919062000abb565b90915550506001600160a01b0384165f9081526004602052604081208054839290620003b290849062000abb565b909155505060e0516040518281526001600160a01b03909116905f905f805160206200613f8339815191529060200160405180910390a360c05162019f9f19906001600160a01b031663f637731d620004156200040f8462000ad7565b620005e5565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024015f604051808303815f87803b15801562000454575f80fd5b505af115801562000467573d5f803e3d5ffd5b50506101005160a05160405163095ea7b360e01b81526001600160a01b0391821660048201525f1960248201529116925063095ea7b391506044016020604051808303815f875af1158015620004bf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620004e5919062000afa565b50610100516101205160405163095ea7b360e01b81526001600160a01b0391821660048201525f19602482015291169063095ea7b3906044016020604051808303815f875af11580156200053b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000561919062000afa565b5050305f818152600560209081526040808320610120516001600160a01b039081168086529184528285205f199081905560a051821686528386205590845260069092528083208054600160ff19918216811790925560e05190931684528184208054841682179055938352909120805490911690911790555062000b9292505050565b5f805f8360020b12620005fc578260020b6200060b565b8260020b6200060b9062000b1b565b9050620d89e8811115620006465760405162461bcd60e51b81526020600482015260016024820152601560fa1b6044820152606401620002ea565b5f816001165f036200065d57600160801b6200066f565b6ffffcb933bd6fad37aa2d162d1a5940015b6001600160881b031690506002821615620006a7576080620006a2826ffff97272373d413259a46990580e213a62000b38565b901c90505b6004821615620006d4576080620006cf826ffff2e50f5f656932ef12357cf3c7fdcc62000b38565b901c90505b600882161562000701576080620006fc826fffe5caca7e10e4e61c3624eaa0941cd062000b38565b901c90505b60108216156200072e57608062000729826fffcb9843d60f6159c9db58835c92664462000b38565b901c90505b60208216156200075b57608062000756826fff973b41fa98c081472e6896dfb254c062000b38565b901c90505b60408216156200078857608062000783826fff2ea16466c96a3843ec78b326b5286162000b38565b901c90505b6080821615620007b5576080620007b0826ffe5dee046a99a2a811c461f1969c305362000b38565b901c90505b610100821615620007e3576080620007de826ffcbe86c7900a88aedcffc83b479aa3a462000b38565b901c90505b610200821615620008115760806200080c826ff987a7253ac413176f2b074cf7815e5462000b38565b901c90505b6104008216156200083f5760806200083a826ff3392b0822b70005940c7a398e4b70f362000b38565b901c90505b6108008216156200086d57608062000868826fe7159475a2c29b7443b29c7fa6e889d962000b38565b901c90505b6110008216156200089b57608062000896826fd097f3bdfd2022b8845ad8f792aa582562000b38565b901c90505b612000821615620008c9576080620008c4826fa9f746462d870fdf8a65dc1f90e061e562000b38565b901c90505b614000821615620008f7576080620008f2826f70d869a156d2a1b890bb3df62baf32f762000b38565b901c90505b6180008216156200092557608062000920826f31be135f97d08fd981231505542fcfa662000b38565b901c90505b62010000821615620009545760806200094f826f09aa508b5b7a84e1c677de54f3e99bc962000b38565b901c90505b62020000821615620009825760806200097d826e5d6af8dedb81196699c329225ee60462000b38565b901c90505b62040000821615620009af576080620009aa826d2216e584f5fa1ea926041bedfe9862000b38565b901c90505b62080000821615620009da576080620009d5826b048a170391f7dc42444e8fa262000b38565b901c90505b5f8460020b1315620009f657620009f3815f1962000b66565b90505b62000a076401000000008262000b7c565b1562000a1557600162000a17565b5f5b62000a2a9060ff16602083901c62000abb565b949350505050565b80516001600160a01b038116811462000a49575f80fd5b919050565b5f806040838503121562000a60575f80fd5b62000a6b8362000a32565b915062000a7b6020840162000a32565b90509250929050565b5f6020828403121562000a95575f80fd5b62000aa08262000a32565b9392505050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111562000ad15762000ad162000aa7565b92915050565b5f8160020b627fffff19810362000af25762000af262000aa7565b5f0392915050565b5f6020828403121562000b0b575f80fd5b8151801515811462000aa0575f80fd5b5f600160ff1b820162000b325762000b3262000aa7565b505f0390565b808202811582820484141762000ad15762000ad162000aa7565b634e487b7160e01b5f52601260045260245ffd5b5f8262000b775762000b7762000b52565b500490565b5f8262000b8d5762000b8d62000b52565b500690565b60805160a05160c05160e0516101005161012051610140516101605161534462000dfb5f395f81816103470152612bfd01525f81816124e001528181612d890152612e8a01525f818161163b015281816117b0015281816120f401528181612fe301528181613335015281816135aa015261401901525f81816106310152818161075e01528181610a4901528181610de501528181610e6701528181610ed301528181610f1d01528181610f720152818161113e015281816111b5015281816112de01528181611459015281816115fb015281816117370152818161203301528181612249015281816125b00152818161265b01528181612858015281816128d3015281816132e1015281816134190152818161345401528181613f95015281816141be01528181614360015281816143e001526147a901525f8181611a9501528181611e9101528181612326015281816128fa015281816129b001528181613c72015261444f01525f818161053f01528181611a2501528181611bbb0152818161237f0152818161245d01528181612ae601528181612c320152818161362501528181613668015281816136a5015281816138ca0152818161394501528181613a1301528181613ad801526144b501525f8181610c9b01528181611c6f01528181611d3401528181611dbd01528181611ec001528181612620015281816127ab01528181612f86015281816132570152818161376c0152818161390701528181613a4e01528181613bc701528181613c19015281816142cd015281816145f4015261476e01525f81816108d401528181610a9d0152818161131e01526114c901526153445ff3fe608060405260043610610191575f3560e01c80636ac5eeee116100dc578063c9567bf911610087578063ea45460b11610062578063ea45460b146104c8578063ea7a61c9146104db578063edd14343146104fa578063f5247e9b14610531575f80fd5b8063c9567bf91461045d578063dd62ed3e14610465578063e9cbafb0146104a9575f80fd5b806395d89b41116100b757806395d89b41146103e55780639a2bb3461461042a578063a9059cbb1461043e575f80fd5b80636ac5eeee1461038a57806370a082311461039e5780637a3e3495146103d2575f80fd5b806323b872dd1161013c578063313ce56711610117578063313ce5671461031b57806332cb6b0c146103365780636299539714610369575f80fd5b806323b872dd146102a65780632ba35fdb146102c55780632ddeb94d146102e4575f80fd5b8063167d58531161016c578063167d58531461024f57806318160ddd1461026257806318bd21b914610276575f80fd5b806306fdde031461019c57806308fafb7c146101f3578063095ea7b314610220575f80fd5b3661019857005b5f80fd5b3480156101a7575f80fd5b5060408051808201909152600a81527f436861696e546f6f6c730000000000000000000000000000000000000000000060208201525b6040516101ea9190614952565b60405180910390f35b3480156101fe575f80fd5b5061021261020d3660046149d6565b610563565b6040519081526020016101ea565b34801561022b575f80fd5b5061023f61023a366004614a42565b610bdc565b60405190151581526020016101ea565b61021261025d366004614a6c565b610c60565b34801561026d575f80fd5b50600354610212565b348015610281575f80fd5b505f546001600160a01b03165b6040516001600160a01b0390911681526020016101ea565b3480156102b1575f80fd5b5061023f6102c0366004614ab5565b611073565b3480156102d0575f80fd5b506102126102df366004614b10565b6110c7565b3480156102ef575f80fd5b5061028e6102fe366004614b90565b6001600160a01b039081165f908152600860205260409020541690565b348015610326575f80fd5b50604051601281526020016101ea565b348015610341575f80fd5b506102127f000000000000000000000000000000000000000000000000000000000000000081565b348015610374575f80fd5b50610388610383366004614bab565b611971565b005b348015610395575f80fd5b50610388611f87565b3480156103a9575f80fd5b506102126103b8366004614b90565b6001600160a01b03165f9081526004602052604090205490565b6102126103e0366004614bf0565b612161565b3480156103f0575f80fd5b5060408051808201909152600481527f43544c530000000000000000000000000000000000000000000000000000000060208201526101dd565b348015610435575f80fd5b506103886122f9565b348015610449575f80fd5b5061023f610458366004614a42565b6124bf565b6103886124d5565b348015610470575f80fd5b5061021261047f366004614c37565b6001600160a01b039182165f90815260056020908152604080832093909416825291909152205490565b3480156104b4575f80fd5b506103886104c3366004614c6e565b612adb565b6103886104d6366004614d2f565b612ce4565b3480156104e6575f80fd5b506103886104f5366004614c37565b612e7f565b348015610505575f80fd5b5061023f610514366004614b90565b6001600160a01b03165f9081526006602052604090205460ff1690565b34801561053c575f80fd5b507f000000000000000000000000000000000000000000000000000000000000000061028e565b604080513360248201526001600160a01b03881660448201819052606480830189905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905291515f92916105ed91614d96565b5f604051808303815f865af19150503d805f8114610626576040519150601f19603f3d011682016040523d82523d5f602084013e61062b565b606091505b5050505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610695573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106b99190614db1565b6040517f89afcb440000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b039182169290921492505f9182918b16906389afcb449060240160408051808303815f875af1158015610721573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107459190614dcc565b9092509050475f846107575782610759565b835b90505f7f000000000000000000000000000000000000000000000000000000000000000090506040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081528260048201525f806024835f865af15050856107c157846107c3565b835b91508c6001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610801573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108259190614db1565b90505f60015f9054906101000a90046001600160a01b03166001600160a01b03166354a26f5c8f6040518263ffffffff1660e01b815260040161087791906001600160a01b0391909116815260200190565b602060405180830381865afa158015610892573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108b69190614db1565b90506001600160a01b038116156109f4576040516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166024830152604482018f90528216907f095ea7b30000000000000000000000000000000000000000000000000000000090606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516109b29190614d96565b5f604051808303815f865af19150503d805f81146109eb576040519150601f19603f3d011682016040523d82523d5f602084013e6109f0565b606091505b5050505b6040805160028082526060820183525f9260208301908036833701905050905081815f81518110610a2757610a27614dee565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000000000000000000000000000000000000000000081600181518110610a7b57610a7b614dee565b60200260200101906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663791ac947858f8430426040518663ffffffff1660e01b8152600401610aef959493929190614e5d565b5f604051808303815f87803b158015610b06575f80fd5b505af1158015610b18573d5f803e3d5ffd5b50309250637a3e34959150610b2f90508747614ed7565b8e338f8f6040518663ffffffff1660e01b8152600401610b8894939291906fffffffffffffffffffffffffffffffff9490941684526001600160a01b039283166020850152604084019190915216606082015260800190565b60206040518083038185885af1158015610ba4573d5f803e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190610bc99190614eea565b9f9e505050505050505050505050505050565b5f610be83384846130eb565b60015474010000000000000000000000000000000000000000900460ff1615610c5657306001600160a01b0316636ac5eeee6040518163ffffffff1660e01b81526004015f604051808303815f87803b158015610c43575f80fd5b505af1925050508015610c54575060015b505b5060015b92915050565b6040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018690525f9033906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015610ce0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d049190614db1565b6001600160a01b031614610d2b5760405163055c501b60e51b815260040160405180910390fd5b6001546040517feb02c301000000000000000000000000000000000000000000000000000000008152600481018890525f91829182916001600160a01b03169063eb02c30190602401606060405180830381865afa158015610d8f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610db39190614f01565b919450925090505f80610ddb8b6064610dcc3487614f40565b610dd69190614fa1565b6131cb565b915091505f610f187f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b031614610e225786610e24565b855b6001546040517fc95e542b0000000000000000000000000000000000000000000000000000000081526001600160a01b038a8116600483015289811660248301527f000000000000000000000000000000000000000000000000000000000000000092169063c95e542b90604401602060405180830381865afa158015610ead573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ed19190614fcf565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168a6001600160a01b031614610f105786610f12565b855b8f6132de565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b031614610f6357610f5e8284614fea565b610f6d565b610f6d8285614fea565b90505f7f000000000000000000000000000000000000000000000000000000000000000090506040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081528260048201525f806024835f865af150506040517f7a3e3495000000000000000000000000000000000000000000000000000000008152600481018d9052336024820152604481018c90526001600160a01b038b1660648201523090637a3e349590849060840160206040518083038185885af115801561103c573d5f803e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906110619190614eea565b9e9d5050505050505050505050505050565b6001600160a01b0383165f9081526005602090815260408083203380855292528220546110ae90869083906110a9908790614ed7565b6130eb565b6110b9858585613621565b5060019150505b9392505050565b6040805133602482015230604482015260648082018a905282518083039091018152608490910182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905290515f917f0000000000000000000000000000000000000000000000000000000000000000916001600160a01b038c169161117291614d96565b5f604051808303815f865af19150503d805f81146111ab576040519150601f19603f3d011682016040523d82523d5f602084013e6111b0565b606091505b5050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168a6001600160a01b0316036112c2576040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081528960048201525f806024835f865af150506040517f7a3e349500000000000000000000000000000000000000000000000000000000815260048101889052336024820152604481018590526001600160a01b03841660648201523090637a3e3495908b9060840160206040518083038185885af1158015611295573d5f803e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906112ba9190614eea565b915050611965565b85156115e5576001600160a01b038a16301480159061131357507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168a6001600160a01b031614155b1561140057604080517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03908116602483015260448083018d905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790529151918c16916113be9190614d96565b5f604051808303815f865af19150503d805f81146113f7576040519150601f19603f3d011682016040523d82523d5f602084013e6113fc565b606091505b5050505b60408051600280825260608201835247925f9291906020830190803683370190505090508b815f8151811061143757611437614dee565b60200260200101906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000000000000000000000000000000000000000000008160018151811061148b5761148b614dee565b6001600160a01b0392831660209182029290920101526040517f791ac9470000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000009091169063791ac94790611508908e908e90869030904290600401614ffd565b5f604051808303815f87803b15801561151f575f80fd5b505af1158015611531573d5f803e3d5ffd5b50309250637a3e3495915061154890508447614ed7565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b168152600481018d9052336024820152604481018a90526001600160a01b038916606482015260840160206040518083038185885af11580156115b6573d5f803e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906115db9190614eea565b9350505050611965565b6001600160a01b038a16301480159061163057507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168a6001600160a01b031614155b1561171d57604080517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03908116602483015260448083018d905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790529151918c16916116db9190614d96565b5f604051808303815f865af19150503d805f8114611714576040519150601f19603f3d011682016040523d82523d5f602084013e611719565b606091505b5050505b60408051610100810182526001600160a01b038c811682527f00000000000000000000000000000000000000000000000000000000000000008116602083015262ffffff88168284015230606083015242608083015260a082018c905260c082018b90525f60e0830181905292517f414bf3890000000000000000000000000000000000000000000000000000000081527f0000000000000000000000000000000000000000000000000000000000000000919091169163414bf3899161185091906004015f610100820190506001600160a01b0380845116835280602085015116602084015262ffffff60408501511660408401528060608501511660608401526080840151608084015260a084015160a084015260c084015160c08401528060e08501511660e08401525092915050565b6020604051808303815f875af115801561186c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118909190614eea565b90506040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081528160048201525f806024835f875af150506040517f7a3e349500000000000000000000000000000000000000000000000000000000815260048101899052336024820152604481018690526001600160a01b03851660648201523090637a3e349590839060840160206040518083038185885af115801561193b573d5f803e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906119609190614eea565b925050505b98975050505050505050565b8261ffff16600503611a8a575f546001600160a01b031633146119a75760405163055c501b60e51b815260040160405180910390fd5b5f6001600160a01b0316816001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119ed573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a119190614db1565b6001600160a01b031603611a23575f80fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031603611a60575f80fd5b6001600160a01b03165f908152600760205260409020805460ff81161560ff199091161790555050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611ad35760405163055c501b60e51b815260040160405180910390fd5b8261ffff165f03611b3d57811580611aeb5750816001145b611af3575f80fd5b600180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16750100000000000000000000000000000000000000000060ff851602179055505050565b8261ffff16600103611b995768056bc75e2d63100000821115611b5e575f80fd5b600280547fffffffffffffffffffffffffffffffffffffffffffff000000000000000000001669ffffffffffffffffffff8416179055505050565b8261ffff16600203611c22576001600160a01b0381163014801590611bf057507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031614155b611bf8575f80fd5b6001600160a01b03165f908152600660205260409020805460ff81161560ff199091161790555050565b8261ffff16600303611e0e576001546040517fa22cb4650000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201525f60248201527f00000000000000000000000000000000000000000000000000000000000000009091169063a22cb465906044015f604051808303815f87803b158015611cb2575f80fd5b505af1158015611cc4573d5f803e3d5ffd5b5050600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0385811691821783556040517fa22cb465000000000000000000000000000000000000000000000000000000008152600481019290925260248201929092527f0000000000000000000000000000000000000000000000000000000000000000909116925063a22cb46591506044015f604051808303815f87803b158015611d79575f80fd5b505af1158015611d8b573d5f803e3d5ffd5b5050506001600160a01b038083165f908152600660209081526040808320805460ff19166001179055600582528083207f00000000000000000000000000000000000000000000000000000000000000009094168352929052207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff905550505050565b8261ffff16600403611f1c57600154611e4a90760100000000000000000000000000000000000000000000900463ffffffff16629e340061501b565b63ffffffff16421015611e5b575f80fd5b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166024830152604482018490527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906064015f604051808303815f87803b158015611f01575f80fd5b505af1158015611f13573d5f803e3d5ffd5b50505050505050565b8261ffff16600603611f8257811580611f355750816001145b611f3d575f80fd5b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000060ff8516021790555b505050565b305f908152600460205260409020546003546107d09004811015611fa85750565b333014801590611fc357506001546001600160a01b03163314155b8015611fd957505f546001600160a01b03163314155b15611ff75760405163055c501b60e51b815260040160405180910390fd5b5f6101906003548161200b5761200b614f74565b0490508082111561201a578091505b6040805161010081018252308082526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166020840190815261271084860190815260608501938452426080860190815260a086018981525f60c0880181815260e0890191825298517f414bf389000000000000000000000000000000000000000000000000000000008152975186166004890152935185166024880152915162ffffff16604487015293518316606486015292516084850152915160a4840152925160c483015251821660e48201527f00000000000000000000000000000000000000000000000000000000000000009091169063414bf38990610104016020604051808303815f875af115801561213d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f829190614eea565b5f805432808352600860205260408320546001600160a01b0392831692908116919085161480159061219a57506001600160a01b038116155b80156121ae57506001600160a01b03841615155b156121f357325f90815260086020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0386161790555b325f908152600860205260409020546001600160a01b0316612216575080612230565b50325f908152600860205260409020546001600160a01b03165b60643490810460038102808201909203916002810490507f00000000000000000000000000000000000000000000000000000000000000005f808080858a5af1505f805f808689611b58f150604051630d0e30db81525f8060048388865af15050846001600160a01b03168a6001600160a01b03167faa63193cea477530e577a5b8c61efd36b21b453c430fdb45e1b7e9fadca44bb7856040516122d691815260200190565b60405180910390a36122ea8b858b8d613dee565b9b9a5050505050505050505050565b33301480159061231457506001546001600160a01b03163314155b80156123495750336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614155b801561235f57505f546001600160a01b03163314155b1561237d5760405163055c501b60e51b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631a6865026040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123d9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123fd919061503f565b6fffffffffffffffffffffffffffffffff16156124bd576040517f490e6cbc0000000000000000000000000000000000000000000000000000000081523060048201525f60248201819052604482018190526080606483015260848201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063490e6cbc9060a4015f604051808303815f87803b1580156124a6575f80fd5b505af11580156124b8573d5f803e3d5ffd5b505050505b565b5f6124cb338484613621565b5060019392505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461251e5760405163055c501b60e51b815260040160405180910390fd5b600180547fffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffff167601000000000000000000000000000000000000000000004263ffffffff16021790557ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe60605f6125928261505a565b905061259f60c882615096565b6125aa9060c8615109565b90505f807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004015f604051808303818588803b158015612607575f80fd5b505af1158015612619573d5f803e3d5ffd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663883164566040518061016001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001306001600160a01b0316815260200161271062ffffff168152602001620668a0876126b39190615128565b60020b81526020016126c887620668a0615169565b60020b8152602001348152602001697f0e10af47c1c700000081526020015f81526020015f8152602001306001600160a01b03168152602001428152506040518263ffffffff1660e01b815260040161272191906151aa565b6080604051808303815f875af115801561273d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612761919061526e565b600180546040517fa22cb4650000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260248101929092529296509094507f0000000000000000000000000000000000000000000000000000000000000000909116925063a22cb46591506044015f604051808303815f87803b1580156127f0575f80fd5b505af1158015612802573d5f803e3d5ffd5b505050505f81697f0e10af47c1c700000061281d9190614ed7565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091505f906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561289d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128c19190614eea565b905080156129aa576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663a9059cbb7f0000000000000000000000000000000000000000000000000000000000000000612924600185614ed7565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303815f875af1158015612984573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129a891906152a9565b505b6129d5307f000000000000000000000000000000000000000000000000000000000000000084614257565b50600180547fffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffffff167a0100000000000000000000000000000000000000000000000000004263ffffffff16021790555f80546040517f760a3ce800000000000000000000000000000000000000000000000000000000815260048101929092526001600160a01b03169063760a3ce8906024015f604051808303815f87803b158015612a7e575f80fd5b505af1158015612a90573d5f803e3d5ffd5b5050600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790555050505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612b245760405163055c501b60e51b815260040160405180910390fd5b6001545f90612b57907a010000000000000000000000000000000000000000000000000000900463ffffffff1642614ed7565b9050610708811115612cdd57612b6b61435e565b600180547fffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffffff167a0100000000000000000000000000000000000000000000000000004263ffffffff160217905560025469ffffffffffffffffffff165f03612bd357506124b8565b6002545f9069ffffffffffffffffffff16612bef603c846152c4565b612bf991906152d7565b90507f000000000000000000000000000000000000000000000000000000000000000081600354612c2a9190614fea565b1015612ca8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165f8181526004602090815260408083208054860190556003805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35b6040518181527f9e53c8c043384f603b9c507779768691e8ffa22fa191bc92f65e71d7eeb76c959060200160405180910390a1505b5050505050565b828114612cef575f80fd5b600154760100000000000000000000000000000000000000000000900463ffffffff1615612d7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f616c72656164795f636f6d706c6574650000000000000000000000000000000060448201526064015b60405180910390fd5b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612dc75760405163055c501b60e51b815260040160405180910390fd5b825f5b81811015612e77575f868683818110612de557612de5614dee565b9050602002016020810190612dfa9190614b90565b90505f858584818110612e0f57612e0f614dee565b6001600160a01b0385165f818152600460209081526040808320948202969096013593849055945183815292955090939092507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050600101612dca565b505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612ec85760405163055c501b60e51b815260040160405180910390fd5b600154760100000000000000000000000000000000000000000000900463ffffffff1615612f22576040517f87822c8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180546001600160a01b038085167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316811784555f908152600660208181526040808420805460ff19908116891790915587548616855260058084528286207f000000000000000000000000000000000000000000000000000000000000000088168088529085528387207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff908190558a54891688528286528488207f00000000000000000000000000000000000000000000000000000000000000008a168952865284882081905587548c8a169a168a1788559887529084528286209086528352818520969096558354909416835252908120805490921690921790556003805469152d02c7e14af6800000929061305f908490614fea565b90915550505f80546001600160a01b03168152600460205260408120805469152d02c7e14af68000009290613095908490614fea565b90915550505f805460405169152d02c7e14af680000081526001600160a01b0390911691907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b6001600160a01b03831661312b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03821661316b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038381165f8181526005602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6040805160a0810182528381526fffffffffffffffffffffffffffffffff838116602083019081525f83850181815260608501828152426080870190815296517f0c49ccbe0000000000000000000000000000000000000000000000000000000081529551600487015292519093166024850152915160448401525160648301529151608482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630c49ccbe9060a40160408051808303815f875af11580156132a4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132c89190614dcc565b50506132d38461456a565b909590945092505050565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316866001600160a01b03161415801561332a57506001600160a01b0386163014155b1561341757604080517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081166024830152604480830187905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790529151918816916133d59190614d96565b5f604051808303815f865af19150503d805f811461340e576040519150601f19603f3d011682016040523d82523d5f602084013e613413565b606091505b5050505b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316866001600160a01b0316148061348857507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b0316145b6134ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f756e737570706f727465645f70616972000000000000000000000000000000006044820152606401612d75565b60408051610100810182526001600160a01b0388811682528781166020830190815262ffffff8881168486019081523060608601908152426080870190815260a087018b815260c088018b81525f60e08a0190815299517f414bf3890000000000000000000000000000000000000000000000000000000081529851881660048a0152955187166024890152925190931660448701525184166064860152905160848501525160a48401525160c48301529151821660e48201527f00000000000000000000000000000000000000000000000000000000000000009091169063414bf38990610104016020604051808303815f875af11580156135f3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136179190614eea565b9695505050505050565b5f807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b0316146136625784613664565b835b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b0316141580156136da57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614155b156136e25750835b600154760100000000000000000000000000000000000000000000900463ffffffff165f0361373d576040517f87822c8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116301480159061376357505f546001600160a01b03828116911614155b80156137a157507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031614155b80156137bb57506001546001600160a01b03828116911614155b15613839576001600160a01b0381165f90815260096020526040902054431115613807576137ea436001614fea565b6001600160a01b0382165f90815260096020526040902055613839565b6040517fc81ae82a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001547501000000000000000000000000000000000000000000900460ff16156138b5576305f5e10083108061387957506a01a784379d99db4200000083115b156138b0576040517f87822c8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6138c8565b6138c0858585614257565b9150506110c0565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b03161415801561393c57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b031614155b801561397a57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614155b15613a11576001600160a01b0384165f9081526007602052604090205460ff16156139b85760405163055c501b60e51b815260040160405180910390fd5b306001600160a01b0316636ac5eeee6040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156139f0575f80fd5b505af1925050508015613a01575060015b156138b5576138c0858585614257565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b03161480613a8257507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b0316145b80613aa457506001600160a01b0385165f9081526006602052604090205460ff165b80613ac657506001600160a01b0384165f9081526006602052604090205460ff165b15613ad6576138c0858585614257565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b031614613b5a57306001600160a01b0316636ac5eeee6040518163ffffffff1660e01b81526004015f604051808303815f87803b158015613b47575f80fd5b505af1925050508015613b58575060015b505b6001600160a01b0385165f9081526004602052604081208054859290613b81908490614ed7565b90915550506001546014840490760100000000000000000000000000000000000000000000900463ffffffff9081166102580116421015613bc0576002025b80840393507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316866001600160a01b031614613c1757305f908152600460205260409020805482019055613d85565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316866001600160a01b031603613d85576001600160a01b038581165f90815260086020526040812054909116613c96577f0000000000000000000000000000000000000000000000000000000000000000613cb1565b6001600160a01b038087165f90815260086020526040902054165b6001600160a01b038082165f818152600460209081526040918290208054600589049081019091559151878152949550909391928a16917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a38083039250816001600160a01b0316876001600160a01b03167faa63193cea477530e577a5b8c61efd36b21b453c430fdb45e1b7e9fadca44bb783604051613d5d91815260200190565b60405180910390a350505f80546001600160a01b031681526004602052604090208054820190555b506001600160a01b038085165f81815260046020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90613ddb9087815260200190565b60405180910390a3506001949350505050565b600154604080517f53aad1d900000000000000000000000000000000000000000000000000000000815290515f9283926001600160a01b0390911691633dc63b739183916353aad1d9916004808201926020929091908290030181865afa158015613e5b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e7f91906152ee565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815260029190910b6004820152602401602060405180830381865afa158015613ed4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ef89190614eea565b6001546040517f7a5a542000000000000000000000000000000000000000000000000000000000815260048101889052602481018390529192505f9182916001600160a01b031690637a5a542090604401602060405180830381865afa158015613f64573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f889190614eea565b60408051610100810182527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081168252306020830181905261271083850152606083015242608083015260a0820184905260c082018c90525f60e083015291517f414bf3890000000000000000000000000000000000000000000000000000000081529293507f0000000000000000000000000000000000000000000000000000000000000000919091169163414bf389916140b8916004015f610100820190506001600160a01b0380845116835280602085015116602084015262ffffff60408501511660408401528060608501511660608401526080840151608084015260a084015160a084015260c084015160c08401528060e08501511660e08401525092915050565b6020604051808303815f875af11580156140d4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906140f89190614eea565b915080870396505f61410c88848989614669565b919650925090508281111561414d576040517f87822c8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b87821115614187576040517f87822c8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526004810187905282890360248201527f0000000000000000000000000000000000000000000000000000000000000000905f8060448382865af150506141f63088848703614257565b5060408051878152602081018a9052908101849052606081018590526001600160a01b038816907fd5928c9413a900ce1d8ea824af263af41ba51a2f90976ca72e9a7f2a68786f979060800160405180910390a25050505050949350505050565b6001600160a01b0383165f90815260046020526040812080548391908390614280908490614ed7565b90915550506001600160a01b038084165f908152600460205260408120805485019055548582169116148015906142c457505f546001600160a01b03848116911614155b801561430257507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031614155b156124cb57826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161434c91815260200190565b60405180910390a35060019392505050565b7f000000000000000000000000000000000000000000000000000000000000000030316402540be4008111156143a457604051630d0e30db81525f8060048385875af150505b506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f906001906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015614425573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906144499190614eea565b0390505f7f000000000000000000000000000000000000000000000000000000000000000090506040517fa9059cbb0000000000000000000000000000000000000000000000000000000081528160048201526064604184020460248201525f806044835f885af150507f000000000000000000000000000000000000000000000000000000000000000090506040517fa9059cbb0000000000000000000000000000000000000000000000000000000081528160048201526064602384020460248201525f806044835f885af150507f1fa911884443714894e04bbf48a5d3c9515fd3ace0c8717542cc75481dfa6ecb6064836023028161454d5761454d614f74565b0460405161455d91815260200190565b60405180910390a1505050565b6040805160808101825282815230602082019081526fffffffffffffffffffffffffffffffff8284018181526060840182815294517ffc6f78650000000000000000000000000000000000000000000000000000000081529351600485015291516001600160a01b039081166024850152915181166044840152925190921660648201525f9182917f00000000000000000000000000000000000000000000000000000000000000009091169063fc6f78659060840160408051808303815f875af115801561463b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061465f9190614dcc565b9094909350915050565b5f805f8060015f9054906101000a90046001600160a01b03166001600160a01b03166353aad1d96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156146bd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906146e191906152ee565b6001546040517f396a28ba000000000000000000000000000000000000000000000000000000008152600481018990529192505f916001600160a01b039091169063396a28ba90602401602060405180830381865afa158015614746573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061476a91906152ee565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663883164566040518061016001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001306001600160a01b0316815260200161271062ffffff1681526020017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2772860020b85876148229190615128565b60020b12614839576148348587615128565b61485b565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff277285b60020b8152602001620d88d86148718688615169565b60020b13614888576148838587615169565b61488d565b620d88d85b60020b81526020018c81526020018b81526020015f81526020015f8152602001896001600160a01b03168152602001428152506040518263ffffffff1660e01b81526004016148dc91906151aa565b6080604051808303815f875af11580156148f8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061491c919061526e565b929c909b5091995090975050505050505050565b5f5b8381101561494a578181015183820152602001614932565b50505f910152565b602081525f8251806020840152614970816040850160208701614930565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6001600160a01b03811681146149b6575f80fd5b50565b6fffffffffffffffffffffffffffffffff811681146149b6575f80fd5b5f805f805f8060c087890312156149eb575f80fd5b86356149f6816149a2565b9550602087013594506040870135614a0d816149b9565b93506060870135614a1d816149b9565b92506080870135915060a0870135614a34816149a2565b809150509295509295509295565b5f8060408385031215614a53575f80fd5b8235614a5e816149a2565b946020939093013593505050565b5f805f805f60a08688031215614a80575f80fd5b853594506020860135935060408601359250606086013591506080860135614aa7816149a2565b809150509295509295909350565b5f805f60608486031215614ac7575f80fd5b8335614ad2816149a2565b92506020840135614ae2816149a2565b929592945050506040919091013590565b80151581146149b6575f80fd5b62ffffff811681146149b6575f80fd5b5f805f805f805f80610100898b031215614b28575f80fd5b8835614b33816149a2565b97506020890135965060408901359550606089013594506080890135614b5881614af3565b935060a0890135614b6881614b00565b925060c0890135915060e0890135614b7f816149a2565b809150509295985092959890939650565b5f60208284031215614ba0575f80fd5b81356110c0816149a2565b5f805f60608486031215614bbd575f80fd5b833561ffff81168114614bce575f80fd5b9250602084013591506040840135614be5816149a2565b809150509250925092565b5f805f8060808587031215614c03575f80fd5b843593506020850135614c15816149a2565b9250604085013591506060850135614c2c816149a2565b939692955090935050565b5f8060408385031215614c48575f80fd5b8235614c53816149a2565b91506020830135614c63816149a2565b809150509250929050565b5f805f8060608587031215614c81575f80fd5b8435935060208501359250604085013567ffffffffffffffff80821115614ca6575f80fd5b818701915087601f830112614cb9575f80fd5b813581811115614cc7575f80fd5b886020828501011115614cd8575f80fd5b95989497505060200194505050565b5f8083601f840112614cf7575f80fd5b50813567ffffffffffffffff811115614d0e575f80fd5b6020830191508360208260051b8501011115614d28575f80fd5b9250929050565b5f805f8060408587031215614d42575f80fd5b843567ffffffffffffffff80821115614d59575f80fd5b614d6588838901614ce7565b90965094506020870135915080821115614d7d575f80fd5b50614d8a87828801614ce7565b95989497509550505050565b5f8251614da7818460208701614930565b9190910192915050565b5f60208284031215614dc1575f80fd5b81516110c0816149a2565b5f8060408385031215614ddd575f80fd5b505080516020909101519092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f8151808452602080850194508084015f5b83811015614e525781516001600160a01b031687529582019590820190600101614e2d565b509495945050505050565b8581526fffffffffffffffffffffffffffffffff8516602082015260a060408201525f614e8d60a0830186614e1b565b6001600160a01b0394909416606083015250608001529392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610c5a57610c5a614eaa565b5f60208284031215614efa575f80fd5b5051919050565b5f805f60608486031215614f13575f80fd5b8351614f1e816149a2565b6020850151909350614f2f816149a2565b6040850151909250614be5816149b9565b6fffffffffffffffffffffffffffffffff818116838216028082169190828114614f6c57614f6c614eaa565b505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f6fffffffffffffffffffffffffffffffff80841680614fc357614fc3614f74565b92169190910492915050565b5f60208284031215614fdf575f80fd5b81516110c081614b00565b80820180821115610c5a57610c5a614eaa565b85815284602082015260a060408201525f614e8d60a0830186614e1b565b63ffffffff81811683821601908082111561503857615038614eaa565b5092915050565b5f6020828403121561504f575f80fd5b81516110c0816149b9565b5f8160020b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800000810361508e5761508e614eaa565b5f0392915050565b5f8160020b8360020b806150ac576150ac614f74565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81147fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000008314161561510057615100614eaa565b90059392505050565b5f8260020b8260020b028060020b915080821461503857615038614eaa565b600282810b9082900b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000008112627fffff82131715610c5a57610c5a614eaa565b600281810b9083900b01627fffff81137fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000082121715610c5a57610c5a614eaa565b81516001600160a01b03168152610160810160208301516151d660208401826001600160a01b03169052565b5060408301516151ed604084018262ffffff169052565b506060830151615202606084018260020b9052565b506080830151615217608084018260020b9052565b5060a083015160a083015260c083015160c083015260e083015160e08301526101008084015181840152506101208084015161525d828501826001600160a01b03169052565b505061014092830151919092015290565b5f805f8060808587031215615281575f80fd5b845193506020850151615293816149b9565b6040860151606090960151949790965092505050565b5f602082840312156152b9575f80fd5b81516110c081614af3565b5f826152d2576152d2614f74565b500490565b8082028115828204841417610c5a57610c5a614eaa565b5f602082840312156152fe575f80fd5b81518060020b81146110c0575f80fdfea26469706673582212203c02c122b6b49b213e73ee446714812766c5b5903c85572ac55546a6751aef4e64736f6c63430008140033ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef000000000000000000000000b0df68e0bf4f54d06a4a448735d2a3d7d97a22220000000000000000000000009318a070a16e25554f098c6930b506123b66e19d

Deployed Bytecode

0x608060405260043610610191575f3560e01c80636ac5eeee116100dc578063c9567bf911610087578063ea45460b11610062578063ea45460b146104c8578063ea7a61c9146104db578063edd14343146104fa578063f5247e9b14610531575f80fd5b8063c9567bf91461045d578063dd62ed3e14610465578063e9cbafb0146104a9575f80fd5b806395d89b41116100b757806395d89b41146103e55780639a2bb3461461042a578063a9059cbb1461043e575f80fd5b80636ac5eeee1461038a57806370a082311461039e5780637a3e3495146103d2575f80fd5b806323b872dd1161013c578063313ce56711610117578063313ce5671461031b57806332cb6b0c146103365780636299539714610369575f80fd5b806323b872dd146102a65780632ba35fdb146102c55780632ddeb94d146102e4575f80fd5b8063167d58531161016c578063167d58531461024f57806318160ddd1461026257806318bd21b914610276575f80fd5b806306fdde031461019c57806308fafb7c146101f3578063095ea7b314610220575f80fd5b3661019857005b5f80fd5b3480156101a7575f80fd5b5060408051808201909152600a81527f436861696e546f6f6c730000000000000000000000000000000000000000000060208201525b6040516101ea9190614952565b60405180910390f35b3480156101fe575f80fd5b5061021261020d3660046149d6565b610563565b6040519081526020016101ea565b34801561022b575f80fd5b5061023f61023a366004614a42565b610bdc565b60405190151581526020016101ea565b61021261025d366004614a6c565b610c60565b34801561026d575f80fd5b50600354610212565b348015610281575f80fd5b505f546001600160a01b03165b6040516001600160a01b0390911681526020016101ea565b3480156102b1575f80fd5b5061023f6102c0366004614ab5565b611073565b3480156102d0575f80fd5b506102126102df366004614b10565b6110c7565b3480156102ef575f80fd5b5061028e6102fe366004614b90565b6001600160a01b039081165f908152600860205260409020541690565b348015610326575f80fd5b50604051601281526020016101ea565b348015610341575f80fd5b506102127f0000000000000000000000000000000000000000000c685fa11e01ec6f00000081565b348015610374575f80fd5b50610388610383366004614bab565b611971565b005b348015610395575f80fd5b50610388611f87565b3480156103a9575f80fd5b506102126103b8366004614b90565b6001600160a01b03165f9081526004602052604090205490565b6102126103e0366004614bf0565b612161565b3480156103f0575f80fd5b5060408051808201909152600481527f43544c530000000000000000000000000000000000000000000000000000000060208201526101dd565b348015610435575f80fd5b506103886122f9565b348015610449575f80fd5b5061023f610458366004614a42565b6124bf565b6103886124d5565b348015610470575f80fd5b5061021261047f366004614c37565b6001600160a01b039182165f90815260056020908152604080832093909416825291909152205490565b3480156104b4575f80fd5b506103886104c3366004614c6e565b612adb565b6103886104d6366004614d2f565b612ce4565b3480156104e6575f80fd5b506103886104f5366004614c37565b612e7f565b348015610505575f80fd5b5061023f610514366004614b90565b6001600160a01b03165f9081526006602052604090205460ff1690565b34801561053c575f80fd5b507f000000000000000000000000c53489f27f4d8a1cdced3bfe397caf628e8abc1361028e565b604080513360248201526001600160a01b03881660448201819052606480830189905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905291515f92916105ed91614d96565b5f604051808303815f865af19150503d805f8114610626576040519150601f19603f3d011682016040523d82523d5f602084013e61062b565b606091505b5050505f7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316886001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610695573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106b99190614db1565b6040517f89afcb440000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b039182169290921492505f9182918b16906389afcb449060240160408051808303815f875af1158015610721573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107459190614dcc565b9092509050475f846107575782610759565b835b90505f7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290506040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081528260048201525f806024835f865af15050856107c157846107c3565b835b91508c6001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610801573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108259190614db1565b90505f60015f9054906101000a90046001600160a01b03166001600160a01b03166354a26f5c8f6040518263ffffffff1660e01b815260040161087791906001600160a01b0391909116815260200190565b602060405180830381865afa158015610892573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108b69190614db1565b90506001600160a01b038116156109f4576040516001600160a01b037f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d81166024830152604482018f90528216907f095ea7b30000000000000000000000000000000000000000000000000000000090606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516109b29190614d96565b5f604051808303815f865af19150503d805f81146109eb576040519150601f19603f3d011682016040523d82523d5f602084013e6109f0565b606091505b5050505b6040805160028082526060820183525f9260208301908036833701905050905081815f81518110610a2757610a27614dee565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281600181518110610a7b57610a7b614dee565b60200260200101906001600160a01b031690816001600160a01b0316815250507f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663791ac947858f8430426040518663ffffffff1660e01b8152600401610aef959493929190614e5d565b5f604051808303815f87803b158015610b06575f80fd5b505af1158015610b18573d5f803e3d5ffd5b50309250637a3e34959150610b2f90508747614ed7565b8e338f8f6040518663ffffffff1660e01b8152600401610b8894939291906fffffffffffffffffffffffffffffffff9490941684526001600160a01b039283166020850152604084019190915216606082015260800190565b60206040518083038185885af1158015610ba4573d5f803e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190610bc99190614eea565b9f9e505050505050505050505050505050565b5f610be83384846130eb565b60015474010000000000000000000000000000000000000000900460ff1615610c5657306001600160a01b0316636ac5eeee6040518163ffffffff1660e01b81526004015f604051808303815f87803b158015610c43575f80fd5b505af1925050508015610c54575060015b505b5060015b92915050565b6040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018690525f9033906001600160a01b037f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe881690636352211e90602401602060405180830381865afa158015610ce0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d049190614db1565b6001600160a01b031614610d2b5760405163055c501b60e51b815260040160405180910390fd5b6001546040517feb02c301000000000000000000000000000000000000000000000000000000008152600481018890525f91829182916001600160a01b03169063eb02c30190602401606060405180830381865afa158015610d8f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610db39190614f01565b919450925090505f80610ddb8b6064610dcc3487614f40565b610dd69190614fa1565b6131cb565b915091505f610f187f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316876001600160a01b031614610e225786610e24565b855b6001546040517fc95e542b0000000000000000000000000000000000000000000000000000000081526001600160a01b038a8116600483015289811660248301527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc292169063c95e542b90604401602060405180830381865afa158015610ead573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ed19190614fcf565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168a6001600160a01b031614610f105786610f12565b855b8f6132de565b90505f7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316876001600160a01b031614610f6357610f5e8284614fea565b610f6d565b610f6d8285614fea565b90505f7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290506040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081528260048201525f806024835f865af150506040517f7a3e3495000000000000000000000000000000000000000000000000000000008152600481018d9052336024820152604481018c90526001600160a01b038b1660648201523090637a3e349590849060840160206040518083038185885af115801561103c573d5f803e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906110619190614eea565b9e9d5050505050505050505050505050565b6001600160a01b0383165f9081526005602090815260408083203380855292528220546110ae90869083906110a9908790614ed7565b6130eb565b6110b9858585613621565b5060019150505b9392505050565b6040805133602482015230604482015260648082018a905282518083039091018152608490910182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905290515f917f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2916001600160a01b038c169161117291614d96565b5f604051808303815f865af19150503d805f81146111ab576040519150601f19603f3d011682016040523d82523d5f602084013e6111b0565b606091505b5050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168a6001600160a01b0316036112c2576040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081528960048201525f806024835f865af150506040517f7a3e349500000000000000000000000000000000000000000000000000000000815260048101889052336024820152604481018590526001600160a01b03841660648201523090637a3e3495908b9060840160206040518083038185885af1158015611295573d5f803e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906112ba9190614eea565b915050611965565b85156115e5576001600160a01b038a16301480159061131357507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168a6001600160a01b031614155b1561140057604080517f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b03908116602483015260448083018d905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790529151918c16916113be9190614d96565b5f604051808303815f865af19150503d805f81146113f7576040519150601f19603f3d011682016040523d82523d5f602084013e6113fc565b606091505b5050505b60408051600280825260608201835247925f9291906020830190803683370190505090508b815f8151811061143757611437614dee565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28160018151811061148b5761148b614dee565b6001600160a01b0392831660209182029290920101526040517f791ac9470000000000000000000000000000000000000000000000000000000081527f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d9091169063791ac94790611508908e908e90869030904290600401614ffd565b5f604051808303815f87803b15801561151f575f80fd5b505af1158015611531573d5f803e3d5ffd5b50309250637a3e3495915061154890508447614ed7565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b168152600481018d9052336024820152604481018a90526001600160a01b038916606482015260840160206040518083038185885af11580156115b6573d5f803e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906115db9190614eea565b9350505050611965565b6001600160a01b038a16301480159061163057507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168a6001600160a01b031614155b1561171d57604080517f000000000000000000000000e592427a0aece92de3edee1f18e0157c058615646001600160a01b03908116602483015260448083018d905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790529151918c16916116db9190614d96565b5f604051808303815f865af19150503d805f8114611714576040519150601f19603f3d011682016040523d82523d5f602084013e611719565b606091505b5050505b60408051610100810182526001600160a01b038c811682527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28116602083015262ffffff88168284015230606083015242608083015260a082018c905260c082018b90525f60e0830181905292517f414bf3890000000000000000000000000000000000000000000000000000000081527f000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564919091169163414bf3899161185091906004015f610100820190506001600160a01b0380845116835280602085015116602084015262ffffff60408501511660408401528060608501511660608401526080840151608084015260a084015160a084015260c084015160c08401528060e08501511660e08401525092915050565b6020604051808303815f875af115801561186c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118909190614eea565b90506040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081528160048201525f806024835f875af150506040517f7a3e349500000000000000000000000000000000000000000000000000000000815260048101899052336024820152604481018690526001600160a01b03851660648201523090637a3e349590839060840160206040518083038185885af115801561193b573d5f803e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906119609190614eea565b925050505b98975050505050505050565b8261ffff16600503611a8a575f546001600160a01b031633146119a75760405163055c501b60e51b815260040160405180910390fd5b5f6001600160a01b0316816001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119ed573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a119190614db1565b6001600160a01b031603611a23575f80fd5b7f000000000000000000000000c53489f27f4d8a1cdced3bfe397caf628e8abc136001600160a01b0316816001600160a01b031603611a60575f80fd5b6001600160a01b03165f908152600760205260409020805460ff81161560ff199091161790555050565b336001600160a01b037f000000000000000000000000b0df68e0bf4f54d06a4a448735d2a3d7d97a22221614611ad35760405163055c501b60e51b815260040160405180910390fd5b8261ffff165f03611b3d57811580611aeb5750816001145b611af3575f80fd5b600180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16750100000000000000000000000000000000000000000060ff851602179055505050565b8261ffff16600103611b995768056bc75e2d63100000821115611b5e575f80fd5b600280547fffffffffffffffffffffffffffffffffffffffffffff000000000000000000001669ffffffffffffffffffff8416179055505050565b8261ffff16600203611c22576001600160a01b0381163014801590611bf057507f000000000000000000000000c53489f27f4d8a1cdced3bfe397caf628e8abc136001600160a01b0316816001600160a01b031614155b611bf8575f80fd5b6001600160a01b03165f908152600660205260409020805460ff81161560ff199091161790555050565b8261ffff16600303611e0e576001546040517fa22cb4650000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201525f60248201527f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe889091169063a22cb465906044015f604051808303815f87803b158015611cb2575f80fd5b505af1158015611cc4573d5f803e3d5ffd5b5050600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0385811691821783556040517fa22cb465000000000000000000000000000000000000000000000000000000008152600481019290925260248201929092527f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe88909116925063a22cb46591506044015f604051808303815f87803b158015611d79575f80fd5b505af1158015611d8b573d5f803e3d5ffd5b5050506001600160a01b038083165f908152600660209081526040808320805460ff19166001179055600582528083207f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe889094168352929052207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff905550505050565b8261ffff16600403611f1c57600154611e4a90760100000000000000000000000000000000000000000000900463ffffffff16629e340061501b565b63ffffffff16421015611e5b575f80fd5b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b037f000000000000000000000000b0df68e0bf4f54d06a4a448735d2a3d7d97a222281166024830152604482018490527f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe8816906323b872dd906064015f604051808303815f87803b158015611f01575f80fd5b505af1158015611f13573d5f803e3d5ffd5b50505050505050565b8261ffff16600603611f8257811580611f355750816001145b611f3d575f80fd5b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000060ff8516021790555b505050565b305f908152600460205260409020546003546107d09004811015611fa85750565b333014801590611fc357506001546001600160a01b03163314155b8015611fd957505f546001600160a01b03163314155b15611ff75760405163055c501b60e51b815260040160405180910390fd5b5f6101906003548161200b5761200b614f74565b0490508082111561201a578091505b6040805161010081018252308082526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281166020840190815261271084860190815260608501938452426080860190815260a086018981525f60c0880181815260e0890191825298517f414bf389000000000000000000000000000000000000000000000000000000008152975186166004890152935185166024880152915162ffffff16604487015293518316606486015292516084850152915160a4840152925160c483015251821660e48201527f000000000000000000000000e592427a0aece92de3edee1f18e0157c058615649091169063414bf38990610104016020604051808303815f875af115801561213d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f829190614eea565b5f805432808352600860205260408320546001600160a01b0392831692908116919085161480159061219a57506001600160a01b038116155b80156121ae57506001600160a01b03841615155b156121f357325f90815260086020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0386161790555b325f908152600860205260409020546001600160a01b0316612216575080612230565b50325f908152600860205260409020546001600160a01b03165b60643490810460038102808201909203916002810490507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25f808080858a5af1505f805f808689611b58f150604051630d0e30db81525f8060048388865af15050846001600160a01b03168a6001600160a01b03167faa63193cea477530e577a5b8c61efd36b21b453c430fdb45e1b7e9fadca44bb7856040516122d691815260200190565b60405180910390a36122ea8b858b8d613dee565b9b9a5050505050505050505050565b33301480159061231457506001546001600160a01b03163314155b80156123495750336001600160a01b037f000000000000000000000000b0df68e0bf4f54d06a4a448735d2a3d7d97a22221614155b801561235f57505f546001600160a01b03163314155b1561237d5760405163055c501b60e51b815260040160405180910390fd5b7f000000000000000000000000c53489f27f4d8a1cdced3bfe397caf628e8abc136001600160a01b0316631a6865026040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123d9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123fd919061503f565b6fffffffffffffffffffffffffffffffff16156124bd576040517f490e6cbc0000000000000000000000000000000000000000000000000000000081523060048201525f60248201819052604482018190526080606483015260848201527f000000000000000000000000c53489f27f4d8a1cdced3bfe397caf628e8abc136001600160a01b03169063490e6cbc9060a4015f604051808303815f87803b1580156124a6575f80fd5b505af11580156124b8573d5f803e3d5ffd5b505050505b565b5f6124cb338484613621565b5060019392505050565b336001600160a01b037f0000000000000000000000009318a070a16e25554f098c6930b506123b66e19d161461251e5760405163055c501b60e51b815260040160405180910390fd5b600180547fffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffff167601000000000000000000000000000000000000000000004263ffffffff16021790557ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe60605f6125928261505a565b905061259f60c882615096565b6125aa9060c8615109565b90505f807f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004015f604051808303818588803b158015612607575f80fd5b505af1158015612619573d5f803e3d5ffd5b50505050507f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe886001600160a01b031663883164566040518061016001604052807f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168152602001306001600160a01b0316815260200161271062ffffff168152602001620668a0876126b39190615128565b60020b81526020016126c887620668a0615169565b60020b8152602001348152602001697f0e10af47c1c700000081526020015f81526020015f8152602001306001600160a01b03168152602001428152506040518263ffffffff1660e01b815260040161272191906151aa565b6080604051808303815f875af115801561273d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612761919061526e565b600180546040517fa22cb4650000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260248101929092529296509094507f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe88909116925063a22cb46591506044015f604051808303815f87803b1580156127f0575f80fd5b505af1158015612802573d5f803e3d5ffd5b505050505f81697f0e10af47c1c700000061281d9190614ed7565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091505f906001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216906370a0823190602401602060405180830381865afa15801561289d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128c19190614eea565b905080156129aa576001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21663a9059cbb7f000000000000000000000000b0df68e0bf4f54d06a4a448735d2a3d7d97a2222612924600185614ed7565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303815f875af1158015612984573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129a891906152a9565b505b6129d5307f000000000000000000000000b0df68e0bf4f54d06a4a448735d2a3d7d97a222284614257565b50600180547fffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffffff167a0100000000000000000000000000000000000000000000000000004263ffffffff16021790555f80546040517f760a3ce800000000000000000000000000000000000000000000000000000000815260048101929092526001600160a01b03169063760a3ce8906024015f604051808303815f87803b158015612a7e575f80fd5b505af1158015612a90573d5f803e3d5ffd5b5050600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790555050505050505050565b336001600160a01b037f000000000000000000000000c53489f27f4d8a1cdced3bfe397caf628e8abc131614612b245760405163055c501b60e51b815260040160405180910390fd5b6001545f90612b57907a010000000000000000000000000000000000000000000000000000900463ffffffff1642614ed7565b9050610708811115612cdd57612b6b61435e565b600180547fffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffffff167a0100000000000000000000000000000000000000000000000000004263ffffffff160217905560025469ffffffffffffffffffff165f03612bd357506124b8565b6002545f9069ffffffffffffffffffff16612bef603c846152c4565b612bf991906152d7565b90507f0000000000000000000000000000000000000000000c685fa11e01ec6f00000081600354612c2a9190614fea565b1015612ca8577f000000000000000000000000c53489f27f4d8a1cdced3bfe397caf628e8abc136001600160a01b03165f8181526004602090815260408083208054860190556003805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35b6040518181527f9e53c8c043384f603b9c507779768691e8ffa22fa191bc92f65e71d7eeb76c959060200160405180910390a1505b5050505050565b828114612cef575f80fd5b600154760100000000000000000000000000000000000000000000900463ffffffff1615612d7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f616c72656164795f636f6d706c6574650000000000000000000000000000000060448201526064015b60405180910390fd5b336001600160a01b037f0000000000000000000000009318a070a16e25554f098c6930b506123b66e19d1614612dc75760405163055c501b60e51b815260040160405180910390fd5b825f5b81811015612e77575f868683818110612de557612de5614dee565b9050602002016020810190612dfa9190614b90565b90505f858584818110612e0f57612e0f614dee565b6001600160a01b0385165f818152600460209081526040808320948202969096013593849055945183815292955090939092507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050600101612dca565b505050505050565b336001600160a01b037f0000000000000000000000009318a070a16e25554f098c6930b506123b66e19d1614612ec85760405163055c501b60e51b815260040160405180910390fd5b600154760100000000000000000000000000000000000000000000900463ffffffff1615612f22576040517f87822c8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180546001600160a01b038085167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316811784555f908152600660208181526040808420805460ff19908116891790915587548616855260058084528286207f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe8888168088529085528387207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff908190558a54891688528286528488207f000000000000000000000000e592427a0aece92de3edee1f18e0157c058615648a168952865284882081905587548c8a169a168a1788559887529084528286209086528352818520969096558354909416835252908120805490921690921790556003805469152d02c7e14af6800000929061305f908490614fea565b90915550505f80546001600160a01b03168152600460205260408120805469152d02c7e14af68000009290613095908490614fea565b90915550505f805460405169152d02c7e14af680000081526001600160a01b0390911691907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b6001600160a01b03831661312b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03821661316b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038381165f8181526005602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6040805160a0810182528381526fffffffffffffffffffffffffffffffff838116602083019081525f83850181815260608501828152426080870190815296517f0c49ccbe0000000000000000000000000000000000000000000000000000000081529551600487015292519093166024850152915160448401525160648301529151608482015281907f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe886001600160a01b031690630c49ccbe9060a40160408051808303815f875af11580156132a4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132c89190614dcc565b50506132d38461456a565b909590945092505050565b5f7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316866001600160a01b03161415801561332a57506001600160a01b0386163014155b1561341757604080517f000000000000000000000000e592427a0aece92de3edee1f18e0157c058615646001600160a01b039081166024830152604480830187905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790529151918816916133d59190614d96565b5f604051808303815f865af19150503d805f811461340e576040519150601f19603f3d011682016040523d82523d5f602084013e613413565b606091505b5050505b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316866001600160a01b0316148061348857507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316856001600160a01b0316145b6134ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f756e737570706f727465645f70616972000000000000000000000000000000006044820152606401612d75565b60408051610100810182526001600160a01b0388811682528781166020830190815262ffffff8881168486019081523060608601908152426080870190815260a087018b815260c088018b81525f60e08a0190815299517f414bf3890000000000000000000000000000000000000000000000000000000081529851881660048a0152955187166024890152925190931660448701525184166064860152905160848501525160a48401525160c48301529151821660e48201527f000000000000000000000000e592427a0aece92de3edee1f18e0157c058615649091169063414bf38990610104016020604051808303815f875af11580156135f3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136179190614eea565b9695505050505050565b5f807f000000000000000000000000c53489f27f4d8a1cdced3bfe397caf628e8abc136001600160a01b0316856001600160a01b0316146136625784613664565b835b90507f000000000000000000000000c53489f27f4d8a1cdced3bfe397caf628e8abc136001600160a01b0316856001600160a01b0316141580156136da57507f000000000000000000000000c53489f27f4d8a1cdced3bfe397caf628e8abc136001600160a01b0316846001600160a01b031614155b156136e25750835b600154760100000000000000000000000000000000000000000000900463ffffffff165f0361373d576040517f87822c8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116301480159061376357505f546001600160a01b03828116911614155b80156137a157507f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe886001600160a01b0316816001600160a01b031614155b80156137bb57506001546001600160a01b03828116911614155b15613839576001600160a01b0381165f90815260096020526040902054431115613807576137ea436001614fea565b6001600160a01b0382165f90815260096020526040902055613839565b6040517fc81ae82a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001547501000000000000000000000000000000000000000000900460ff16156138b5576305f5e10083108061387957506a01a784379d99db4200000083115b156138b0576040517f87822c8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6138c8565b6138c0858585614257565b9150506110c0565b7f000000000000000000000000c53489f27f4d8a1cdced3bfe397caf628e8abc136001600160a01b0316856001600160a01b03161415801561393c57507f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe886001600160a01b0316856001600160a01b031614155b801561397a57507f000000000000000000000000c53489f27f4d8a1cdced3bfe397caf628e8abc136001600160a01b0316846001600160a01b031614155b15613a11576001600160a01b0384165f9081526007602052604090205460ff16156139b85760405163055c501b60e51b815260040160405180910390fd5b306001600160a01b0316636ac5eeee6040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156139f0575f80fd5b505af1925050508015613a01575060015b156138b5576138c0858585614257565b7f000000000000000000000000c53489f27f4d8a1cdced3bfe397caf628e8abc136001600160a01b0316846001600160a01b03161480613a8257507f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe886001600160a01b0316846001600160a01b0316145b80613aa457506001600160a01b0385165f9081526006602052604090205460ff165b80613ac657506001600160a01b0384165f9081526006602052604090205460ff165b15613ad6576138c0858585614257565b7f000000000000000000000000c53489f27f4d8a1cdced3bfe397caf628e8abc136001600160a01b0316856001600160a01b031614613b5a57306001600160a01b0316636ac5eeee6040518163ffffffff1660e01b81526004015f604051808303815f87803b158015613b47575f80fd5b505af1925050508015613b58575060015b505b6001600160a01b0385165f9081526004602052604081208054859290613b81908490614ed7565b90915550506001546014840490760100000000000000000000000000000000000000000000900463ffffffff9081166102580116421015613bc0576002025b80840393507f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe886001600160a01b0316866001600160a01b031614613c1757305f908152600460205260409020805482019055613d85565b7f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe886001600160a01b0316866001600160a01b031603613d85576001600160a01b038581165f90815260086020526040812054909116613c96577f000000000000000000000000b0df68e0bf4f54d06a4a448735d2a3d7d97a2222613cb1565b6001600160a01b038087165f90815260086020526040902054165b6001600160a01b038082165f818152600460209081526040918290208054600589049081019091559151878152949550909391928a16917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a38083039250816001600160a01b0316876001600160a01b03167faa63193cea477530e577a5b8c61efd36b21b453c430fdb45e1b7e9fadca44bb783604051613d5d91815260200190565b60405180910390a350505f80546001600160a01b031681526004602052604090208054820190555b506001600160a01b038085165f81815260046020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90613ddb9087815260200190565b60405180910390a3506001949350505050565b600154604080517f53aad1d900000000000000000000000000000000000000000000000000000000815290515f9283926001600160a01b0390911691633dc63b739183916353aad1d9916004808201926020929091908290030181865afa158015613e5b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e7f91906152ee565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815260029190910b6004820152602401602060405180830381865afa158015613ed4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ef89190614eea565b6001546040517f7a5a542000000000000000000000000000000000000000000000000000000000815260048101889052602481018390529192505f9182916001600160a01b031690637a5a542090604401602060405180830381865afa158015613f64573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f889190614eea565b60408051610100810182527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b039081168252306020830181905261271083850152606083015242608083015260a0820184905260c082018c90525f60e083015291517f414bf3890000000000000000000000000000000000000000000000000000000081529293507f000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564919091169163414bf389916140b8916004015f610100820190506001600160a01b0380845116835280602085015116602084015262ffffff60408501511660408401528060608501511660608401526080840151608084015260a084015160a084015260c084015160c08401528060e08501511660e08401525092915050565b6020604051808303815f875af11580156140d4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906140f89190614eea565b915080870396505f61410c88848989614669565b919650925090508281111561414d576040517f87822c8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b87821115614187576040517f87822c8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526004810187905282890360248201527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2905f8060448382865af150506141f63088848703614257565b5060408051878152602081018a9052908101849052606081018590526001600160a01b038816907fd5928c9413a900ce1d8ea824af263af41ba51a2f90976ca72e9a7f2a68786f979060800160405180910390a25050505050949350505050565b6001600160a01b0383165f90815260046020526040812080548391908390614280908490614ed7565b90915550506001600160a01b038084165f908152600460205260408120805485019055548582169116148015906142c457505f546001600160a01b03848116911614155b801561430257507f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe886001600160a01b0316836001600160a01b031614155b156124cb57826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161434c91815260200190565b60405180910390a35060019392505050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc230316402540be4008111156143a457604051630d0e30db81525f8060048385875af150505b506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f906001906001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216906370a0823190602401602060405180830381865afa158015614425573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906144499190614eea565b0390505f7f000000000000000000000000b0df68e0bf4f54d06a4a448735d2a3d7d97a222290506040517fa9059cbb0000000000000000000000000000000000000000000000000000000081528160048201526064604184020460248201525f806044835f885af150507f000000000000000000000000c53489f27f4d8a1cdced3bfe397caf628e8abc1390506040517fa9059cbb0000000000000000000000000000000000000000000000000000000081528160048201526064602384020460248201525f806044835f885af150507f1fa911884443714894e04bbf48a5d3c9515fd3ace0c8717542cc75481dfa6ecb6064836023028161454d5761454d614f74565b0460405161455d91815260200190565b60405180910390a1505050565b6040805160808101825282815230602082019081526fffffffffffffffffffffffffffffffff8284018181526060840182815294517ffc6f78650000000000000000000000000000000000000000000000000000000081529351600485015291516001600160a01b039081166024850152915181166044840152925190921660648201525f9182917f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe889091169063fc6f78659060840160408051808303815f875af115801561463b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061465f9190614dcc565b9094909350915050565b5f805f8060015f9054906101000a90046001600160a01b03166001600160a01b03166353aad1d96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156146bd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906146e191906152ee565b6001546040517f396a28ba000000000000000000000000000000000000000000000000000000008152600481018990529192505f916001600160a01b039091169063396a28ba90602401602060405180830381865afa158015614746573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061476a91906152ee565b90507f000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe886001600160a01b031663883164566040518061016001604052807f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168152602001306001600160a01b0316815260200161271062ffffff1681526020017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2772860020b85876148229190615128565b60020b12614839576148348587615128565b61485b565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff277285b60020b8152602001620d88d86148718688615169565b60020b13614888576148838587615169565b61488d565b620d88d85b60020b81526020018c81526020018b81526020015f81526020015f8152602001896001600160a01b03168152602001428152506040518263ffffffff1660e01b81526004016148dc91906151aa565b6080604051808303815f875af11580156148f8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061491c919061526e565b929c909b5091995090975050505050505050565b5f5b8381101561494a578181015183820152602001614932565b50505f910152565b602081525f8251806020840152614970816040850160208701614930565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6001600160a01b03811681146149b6575f80fd5b50565b6fffffffffffffffffffffffffffffffff811681146149b6575f80fd5b5f805f805f8060c087890312156149eb575f80fd5b86356149f6816149a2565b9550602087013594506040870135614a0d816149b9565b93506060870135614a1d816149b9565b92506080870135915060a0870135614a34816149a2565b809150509295509295509295565b5f8060408385031215614a53575f80fd5b8235614a5e816149a2565b946020939093013593505050565b5f805f805f60a08688031215614a80575f80fd5b853594506020860135935060408601359250606086013591506080860135614aa7816149a2565b809150509295509295909350565b5f805f60608486031215614ac7575f80fd5b8335614ad2816149a2565b92506020840135614ae2816149a2565b929592945050506040919091013590565b80151581146149b6575f80fd5b62ffffff811681146149b6575f80fd5b5f805f805f805f80610100898b031215614b28575f80fd5b8835614b33816149a2565b97506020890135965060408901359550606089013594506080890135614b5881614af3565b935060a0890135614b6881614b00565b925060c0890135915060e0890135614b7f816149a2565b809150509295985092959890939650565b5f60208284031215614ba0575f80fd5b81356110c0816149a2565b5f805f60608486031215614bbd575f80fd5b833561ffff81168114614bce575f80fd5b9250602084013591506040840135614be5816149a2565b809150509250925092565b5f805f8060808587031215614c03575f80fd5b843593506020850135614c15816149a2565b9250604085013591506060850135614c2c816149a2565b939692955090935050565b5f8060408385031215614c48575f80fd5b8235614c53816149a2565b91506020830135614c63816149a2565b809150509250929050565b5f805f8060608587031215614c81575f80fd5b8435935060208501359250604085013567ffffffffffffffff80821115614ca6575f80fd5b818701915087601f830112614cb9575f80fd5b813581811115614cc7575f80fd5b886020828501011115614cd8575f80fd5b95989497505060200194505050565b5f8083601f840112614cf7575f80fd5b50813567ffffffffffffffff811115614d0e575f80fd5b6020830191508360208260051b8501011115614d28575f80fd5b9250929050565b5f805f8060408587031215614d42575f80fd5b843567ffffffffffffffff80821115614d59575f80fd5b614d6588838901614ce7565b90965094506020870135915080821115614d7d575f80fd5b50614d8a87828801614ce7565b95989497509550505050565b5f8251614da7818460208701614930565b9190910192915050565b5f60208284031215614dc1575f80fd5b81516110c0816149a2565b5f8060408385031215614ddd575f80fd5b505080516020909101519092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f8151808452602080850194508084015f5b83811015614e525781516001600160a01b031687529582019590820190600101614e2d565b509495945050505050565b8581526fffffffffffffffffffffffffffffffff8516602082015260a060408201525f614e8d60a0830186614e1b565b6001600160a01b0394909416606083015250608001529392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610c5a57610c5a614eaa565b5f60208284031215614efa575f80fd5b5051919050565b5f805f60608486031215614f13575f80fd5b8351614f1e816149a2565b6020850151909350614f2f816149a2565b6040850151909250614be5816149b9565b6fffffffffffffffffffffffffffffffff818116838216028082169190828114614f6c57614f6c614eaa565b505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f6fffffffffffffffffffffffffffffffff80841680614fc357614fc3614f74565b92169190910492915050565b5f60208284031215614fdf575f80fd5b81516110c081614b00565b80820180821115610c5a57610c5a614eaa565b85815284602082015260a060408201525f614e8d60a0830186614e1b565b63ffffffff81811683821601908082111561503857615038614eaa565b5092915050565b5f6020828403121561504f575f80fd5b81516110c0816149b9565b5f8160020b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800000810361508e5761508e614eaa565b5f0392915050565b5f8160020b8360020b806150ac576150ac614f74565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81147fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000008314161561510057615100614eaa565b90059392505050565b5f8260020b8260020b028060020b915080821461503857615038614eaa565b600282810b9082900b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000008112627fffff82131715610c5a57610c5a614eaa565b600281810b9083900b01627fffff81137fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000082121715610c5a57610c5a614eaa565b81516001600160a01b03168152610160810160208301516151d660208401826001600160a01b03169052565b5060408301516151ed604084018262ffffff169052565b506060830151615202606084018260020b9052565b506080830151615217608084018260020b9052565b5060a083015160a083015260c083015160c083015260e083015160e08301526101008084015181840152506101208084015161525d828501826001600160a01b03169052565b505061014092830151919092015290565b5f805f8060808587031215615281575f80fd5b845193506020850151615293816149b9565b6040860151606090960151949790965092505050565b5f602082840312156152b9575f80fd5b81516110c081614af3565b5f826152d2576152d2614f74565b500490565b8082028115828204841417610c5a57610c5a614eaa565b5f602082840312156152fe575f80fd5b81518060020b81146110c0575f80fdfea26469706673582212203c02c122b6b49b213e73ee446714812766c5b5903c85572ac55546a6751aef4e64736f6c63430008140033

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

000000000000000000000000b0df68e0bf4f54d06a4a448735d2a3d7d97a22220000000000000000000000009318a070a16e25554f098c6930b506123b66e19d

-----Decoded View---------------
Arg [0] : _multisig (address): 0xb0Df68E0bf4F54D06A4a448735D2a3d7D97A2222
Arg [1] : _apest (address): 0x9318a070a16E25554f098c6930B506123b66E19d

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000b0df68e0bf4f54d06a4a448735d2a3d7d97a2222
Arg [1] : 0000000000000000000000009318a070a16e25554f098c6930b506123b66e19d


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.