ETH Price: $3,163.52 (+1.39%)
Gas: 2 Gwei

Contract

0xE155F64B9aD8c81318c313196a60c72e72fD2cD1
 

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Approve202500202024-07-06 21:01:117 days ago1720299671IN
Chaintools: Old CTLS Token
0 ETH0.000072841.50217063
Approve202191092024-07-02 13:24:1111 days ago1719926651IN
Chaintools: Old CTLS Token
0 ETH0.000285935.89758671
Approve202132862024-07-01 17:53:3512 days ago1719856415IN
Chaintools: Old CTLS Token
0 ETH0.000326486.73402355
Approve201854362024-06-27 20:32:5916 days ago1719520379IN
Chaintools: Old CTLS Token
0 ETH0.000257595.31316575
Approve198159852024-05-07 5:04:1167 days ago1715058251IN
Chaintools: Old CTLS Token
0 ETH0.00010333.91068977
Transfer195909882024-04-05 17:21:3599 days ago1712337695IN
Chaintools: Old CTLS Token
0 ETH0.0016514626.58373885
Approve194202202024-03-12 16:34:11123 days ago1710261251IN
Chaintools: Old CTLS Token
0 ETH0.0041611785.44672958
Approve193247152024-02-28 8:02:35136 days ago1709107355IN
Chaintools: Old CTLS Token
0 ETH0.0022600946.40942998
Transfer191169242024-01-30 4:25:59165 days ago1706588759IN
Chaintools: Old CTLS Token
0 ETH0.0006173810.77032162
Approve189326552024-01-04 8:03:59191 days ago1704355439IN
Chaintools: Old CTLS Token
0 ETH0.0004630117.48873102
Approve189326552024-01-04 8:03:59191 days ago1704355439IN
Chaintools: Old CTLS Token
0 ETH0.0004630117.48873102
Approve189326542024-01-04 8:03:47191 days ago1704355427IN
Chaintools: Old CTLS Token
0 ETH0.0004808818.20493619
Approve188634462023-12-25 14:51:11201 days ago1703515871IN
Chaintools: Old CTLS Token
0 ETH0.0006463424.46897164
Transfer186153272023-11-20 20:17:59236 days ago1700511479IN
Chaintools: Old CTLS Token
0 ETH0.0015412234.24103502
Transfer186152922023-11-20 20:10:59236 days ago1700511059IN
Chaintools: Old CTLS Token
0 ETH0.0022081135.56480423
Transfer185299712023-11-08 21:37:59247 days ago1699479479IN
Chaintools: Old CTLS Token
0 ETH0.0024921543.47570088
Approve184916962023-11-03 13:01:23253 days ago1699016483IN
Chaintools: Old CTLS Token
0 ETH0.0012024624.82643222
Approve184731302023-10-31 22:37:11255 days ago1698791831IN
Chaintools: Old CTLS Token
0 ETH0.0009687519.86828821
Transfer184247242023-10-25 3:56:47262 days ago1698206207IN
Chaintools: Old CTLS Token
0 ETH0.0006627810.6750874
Approve184235002023-10-24 23:50:11262 days ago1698191411IN
Chaintools: Old CTLS Token
0 ETH0.000529520
Approve184235002023-10-24 23:50:11262 days ago1698191411IN
Chaintools: Old CTLS Token
0 ETH0.000529520
Transfer183817912023-10-19 3:45:35268 days ago1697687135IN
Chaintools: Old CTLS Token
0 ETH0.000361886.31433509
Approve183736172023-10-18 0:17:47269 days ago1697588267IN
Chaintools: Old CTLS Token
0 ETH0.000351367.20623525
Approve183633832023-10-16 13:57:59271 days ago1697464679IN
Chaintools: Old CTLS Token
0 ETH0.0023025247.46782369
Transfer183406742023-10-13 9:47:47274 days ago1697190467IN
Chaintools: Old CTLS Token
0 ETH0.000284517.07550997
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
177958262023-07-29 2:50:23350 days ago1690599023
Chaintools: Old CTLS Token
0.00225 ETH
177891352023-07-28 4:21:23351 days ago1690518083
Chaintools: Old CTLS Token
0.144 ETH
177891352023-07-28 4:21:23351 days ago1690518083
Chaintools: Old CTLS Token
0.0015 ETH
177891352023-07-28 4:21:23351 days ago1690518083
Chaintools: Old CTLS Token
0.00225 ETH
177625522023-07-24 11:05:47355 days ago1690196747
Chaintools: Old CTLS Token
0.00712199 ETH
177592252023-07-23 23:54:59355 days ago1690156499
Chaintools: Old CTLS Token
0.45580767 ETH
177592252023-07-23 23:54:59355 days ago1690156499
Chaintools: Old CTLS Token
0.00474799 ETH
177592252023-07-23 23:54:59355 days ago1690156499
Chaintools: Old CTLS Token
0.00712199 ETH
177592252023-07-23 23:54:59355 days ago1690156499
Chaintools: Old CTLS Token
0.47479965 ETH
177371372023-07-20 21:44:35358 days ago1689889475
Chaintools: Old CTLS Token
0.00075 ETH
177344342023-07-20 12:40:11359 days ago1689856811
Chaintools: Old CTLS Token
0.048 ETH
177344342023-07-20 12:40:11359 days ago1689856811
Chaintools: Old CTLS Token
0.0005 ETH
177344342023-07-20 12:40:11359 days ago1689856811
Chaintools: Old CTLS Token
0.00075 ETH
177330022023-07-20 7:50:59359 days ago1689839459
Chaintools: Old CTLS Token
0.00105 ETH
177313502023-07-20 2:18:23359 days ago1689819503
Chaintools: Old CTLS Token
0.0672 ETH
177313502023-07-20 2:18:23359 days ago1689819503
Chaintools: Old CTLS Token
0.0007 ETH
177313502023-07-20 2:18:23359 days ago1689819503
Chaintools: Old CTLS Token
0.00105 ETH
177297892023-07-19 21:02:59360 days ago1689800579
Chaintools: Old CTLS Token
0.0045 ETH
177295202023-07-19 20:09:11360 days ago1689797351
Chaintools: Old CTLS Token
0.288 ETH
177295202023-07-19 20:09:11360 days ago1689797351
Chaintools: Old CTLS Token
0.003 ETH
177295202023-07-19 20:09:11360 days ago1689797351
Chaintools: Old CTLS Token
0.0045 ETH
177268172023-07-19 11:04:11360 days ago1689764651
Chaintools: Old CTLS Token
0.075 ETH
177260492023-07-19 8:28:23360 days ago1689755303
Chaintools: Old CTLS Token
4.8 ETH
177260492023-07-19 8:28:23360 days ago1689755303
Chaintools: Old CTLS Token
0.05 ETH
177260492023-07-19 8:28:23360 days ago1689755303
Chaintools: Old CTLS Token
0.075 ETH
View All Internal Transactions
Loading...
Loading

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


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

OVERVIEW

ChainTools are revolutionizing the DeFi landscape by offering the no-staking liquidity rewards protocol.

Validator Index Block Amount
View All Withdrawals

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

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