ETH Price: $3,404.11 (+2.77%)

Contract

0x62e31802c6145A2D5E842EeD8efe01fC224422fA
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Input Single Wit...212345502024-11-21 7:15:112 days ago1732173311IN
0x62e31802...C224422fA
0 ETH0.0013898610.43277259
Input Single Wit...212239922024-11-19 19:52:233 days ago1732045943IN
0x62e31802...C224422fA
0.01 ETH0.00241219.53610817
Input Single Wit...212095882024-11-17 19:42:235 days ago1731872543IN
0x62e31802...C224422fA
0 ETH0.0010756510.99656829
Input Single Wit...211986562024-11-16 7:06:477 days ago1731740807IN
0x62e31802...C224422fA
0.01 ETH0.0016050113
Input Single Wit...211972662024-11-16 2:27:597 days ago1731724079IN
0x62e31802...C224422fA
0 ETH0.001542112.94430948
Input Single Wit...211815212024-11-13 21:41:119 days ago1731534071IN
0x62e31802...C224422fA
0.002 ETH0.0077731155.03050402
Input Single Wit...211782912024-11-13 10:51:4710 days ago1731495107IN
0x62e31802...C224422fA
0 ETH0.0030192228.69358319
Input Single Wit...211763932024-11-13 4:30:4710 days ago1731472247IN
0x62e31802...C224422fA
0 ETH0.0024077224.88504745
Input Single Wit...211745672024-11-12 22:23:3510 days ago1731450215IN
0x62e31802...C224422fA
0.01 ETH0.0044355132.44491729
Input Single Wit...211745662024-11-12 22:23:2310 days ago1731450203IN
0x62e31802...C224422fA
0.01299999 ETH0.0045454533.24327204
Input Single Wit...211745652024-11-12 22:23:1110 days ago1731450191IN
0x62e31802...C224422fA
0.012 ETH0.0036056430.14528803
Input Single Wit...211745632024-11-12 22:22:4710 days ago1731450167IN
0x62e31802...C224422fA
0.01099999 ETH0.00429232.15154373
Input Single Wit...211745632024-11-12 22:22:4710 days ago1731450167IN
0x62e31802...C224422fA
0.012 ETH0.004395432.15154373
Input Single Wit...211745602024-11-12 22:22:1110 days ago1731450131IN
0x62e31802...C224422fA
0.012 ETH0.0043510832.6
Input Single Wit...211745602024-11-12 22:22:1110 days ago1731450131IN
0x62e31802...C224422fA
0.01099999 ETH0.0044574932.6
Input Single Wit...211679272024-11-12 0:08:4711 days ago1731370127IN
0x62e31802...C224422fA
0 ETH0.0038961439.93549691
Input Single Wit...211678162024-11-11 23:46:3511 days ago1731368795IN
0x62e31802...C224422fA
0 ETH0.0040384834.01234191
Input Single Wit...211676252024-11-11 23:08:2311 days ago1731366503IN
0x62e31802...C224422fA
0 ETH0.0038318233.02980947
Input Single Wit...211548982024-11-10 4:32:4713 days ago1731213167IN
0x62e31802...C224422fA
0 ETH0.001225389.71105524
Input Single Wit...211548932024-11-10 4:31:4713 days ago1731213107IN
0x62e31802...C224422fA
0.00016776 ETH0.001245269.28051804
Input Single Wit...211538122024-11-10 0:54:3513 days ago1731200075IN
0x62e31802...C224422fA
0 ETH0.0015579411.68749992
Input Single Wit...211324832024-11-07 1:26:4716 days ago1730942807IN
0x62e31802...C224422fA
0 ETH0.0025769921.72464635
Input Single Wit...211280802024-11-06 10:41:4717 days ago1730889707IN
0x62e31802...C224422fA
0 ETH0.0017604314.84222324
Input Single Wit...211279552024-11-06 10:16:4717 days ago1730888207IN
0x62e31802...C224422fA
0.001 ETH0.0016054313.00336729
Input Single Wit...211263652024-11-06 4:56:4717 days ago1730869007IN
0x62e31802...C224422fA
0.049 ETH0.0030198925.2
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
212239922024-11-19 19:52:233 days ago1732045943
0x62e31802...C224422fA
0.01 ETH
211986562024-11-16 7:06:477 days ago1731740807
0x62e31802...C224422fA
0.01 ETH
211815212024-11-13 21:41:119 days ago1731534071
0x62e31802...C224422fA
0.002 ETH
211745672024-11-12 22:23:3510 days ago1731450215
0x62e31802...C224422fA
0.01 ETH
211745662024-11-12 22:23:2310 days ago1731450203
0x62e31802...C224422fA
0.01299999 ETH
211745652024-11-12 22:23:1110 days ago1731450191
0x62e31802...C224422fA
0.012 ETH
211745632024-11-12 22:22:4710 days ago1731450167
0x62e31802...C224422fA
0.01099999 ETH
211745632024-11-12 22:22:4710 days ago1731450167
0x62e31802...C224422fA
0.012 ETH
211745602024-11-12 22:22:1110 days ago1731450131
0x62e31802...C224422fA
0.012 ETH
211745602024-11-12 22:22:1110 days ago1731450131
0x62e31802...C224422fA
0.01099999 ETH
211548932024-11-10 4:31:4713 days ago1731213107
0x62e31802...C224422fA
0.00016776 ETH
211279552024-11-06 10:16:4717 days ago1730888207
0x62e31802...C224422fA
0.001 ETH
211263652024-11-06 4:56:4717 days ago1730869007
0x62e31802...C224422fA
0.049 ETH
211240982024-11-05 21:21:3517 days ago1730841695
0x62e31802...C224422fA
0.0577 ETH
211012792024-11-02 16:54:5920 days ago1730566499
0x62e31802...C224422fA
0.29999999 ETH
210970192024-11-02 2:36:4721 days ago1730515007
0x62e31802...C224422fA
0.001 ETH
210785122024-10-30 12:39:2324 days ago1730291963
0x62e31802...C224422fA
0.00001 ETH
210328582024-10-24 3:46:1130 days ago1729741571
0x62e31802...C224422fA
0.02 ETH
210194552024-10-22 6:53:3532 days ago1729580015
0x62e31802...C224422fA
0.0001 ETH
210145722024-10-21 14:32:2333 days ago1729521143
0x62e31802...C224422fA
0.0003 ETH
210145612024-10-21 14:30:1133 days ago1729521011
0x62e31802...C224422fA
0.0007 ETH
209857432024-10-17 13:59:5937 days ago1729173599
0x62e31802...C224422fA
0.0001 ETH
209766182024-10-16 7:25:4738 days ago1729063547
0x62e31802...C224422fA
0.02 ETH
209714432024-10-15 14:04:3539 days ago1729001075
0x62e31802...C224422fA
0.000013 ETH
209690862024-10-15 6:10:2339 days ago1728972623
0x62e31802...C224422fA
0.001 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MaverickV2Router

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 5500 runs

Other Settings:
paris EvmVersion
File 1 of 34 : MaverickV2Router.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IMaverickV2Factory} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Factory.sol";

import {IMaverickV2Router} from "./interfaces/IMaverickV2Router.sol";
import {CallbackOperations} from "./routerbase/CallbackOperations.sol";
import {PushOperations} from "./routerbase/PushOperations.sol";
import {Checks} from "./base/Checks.sol";
import {State} from "./paymentbase/State.sol";
import {IWETH9} from "./paymentbase/IWETH9.sol";

/**
 * @notice Swap router functions for Maverick V2.  This contract requires that
 * users approve a spending allowance in order to pay for swaps.
 *
 * @notice The functions in this contract are partitioned into two subcontracts that
 * implement both push-based and callback-based swaps.  Maverick V2 provides
 * two mechanisms for paying for a swap:
 * - Push the input assets to the pool and then call swap.  This avoids a
 * callback to transfer the input assets and is generally more gas efficient but
 * is only suitable for exact-input swaps where the caller knows how much input
 * they need to send to the pool.
 * - Callback payment where the pool calls a callback function on this router
 * to settle up for the input amount of the swap.
 */
contract MaverickV2Router is Checks, PushOperations, CallbackOperations, IMaverickV2Router {
    constructor(IMaverickV2Factory _factory, IWETH9 _weth) State(_factory, _weth) {}
}

File 2 of 34 : IPayableMulticall.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// As the copyright holder of this work, Ubiquity Labs retains
// the right to distribute, use, and modify this code under any license of
// their choosing, in addition to the terms of the GPL-v2 or later.
pragma solidity ^0.8.25;

interface IPayableMulticall {
    function multicall(bytes[] calldata data) external payable returns (bytes[] memory results);
}

File 3 of 34 : PayableMulticall.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// As the copyright holder of this work, Ubiquity Labs retains
// the right to distribute, use, and modify this code under any license of
// their choosing, in addition to the terms of the GPL-v2 or later.
pragma solidity ^0.8.25;
import {IPayableMulticall} from "./IPayableMulticall.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

// Modified from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/6ba452dea4258afe77726293435f10baf2bed265/contracts/utils/Multicall.sol

/*
 * @notice Payable multicall; requires all functions in the multicall to also be
 * payable.
 */
abstract contract PayableMulticall is IPayableMulticall {
    /**
     * @dev This function allows multiple calls to different contract functions
     * in a single transaction.
     * @param data An array of encoded function call data.
     * @return results An array of the results of the function calls.
     */
    function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            results[i] = Address.functionDelegateCall(address(this), data[i]);
        }
    }
}

File 4 of 34 : IMaverickV2Factory.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// As the copyright holder of this work, Ubiquity Labs retains
// the right to distribute, use, and modify this code under any license of
// their choosing, in addition to the terms of the GPL-v2 or later.
pragma solidity ^0.8.25;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import {IMaverickV2Pool} from "./IMaverickV2Pool.sol";

interface IMaverickV2Factory {
    error FactoryInvalidProtocolFeeRatio(uint8 protocolFeeRatioD3);
    error FactoryInvalidLendingFeeRate(uint256 protocolLendingFeeRateD18);
    error FactoryProtocolFeeOnRenounce(uint8 protocolFeeRatioD3);
    error FactorAlreadyInitialized();
    error FactorNotInitialized();
    error FactoryInvalidTokenOrder(IERC20 _tokenA, IERC20 _tokenB);
    error FactoryInvalidFee();
    error FactoryInvalidKinds(uint8 kinds);
    error FactoryInvalidTickSpacing(uint256 tickSpacing);
    error FactoryInvalidLookback(uint256 lookback);
    error FactoryInvalidTokenDecimals(uint8 decimalsA, uint8 decimalsB);
    error FactoryPoolAlreadyExists(
        uint256 feeAIn,
        uint256 feeBIn,
        uint256 tickSpacing,
        uint256 lookback,
        IERC20 tokenA,
        IERC20 tokenB,
        uint8 kinds,
        address accessor
    );
    error FactoryAccessorMustBeNonZero();

    event PoolCreated(
        IMaverickV2Pool poolAddress,
        uint8 protocolFeeRatio,
        uint256 feeAIn,
        uint256 feeBIn,
        uint256 tickSpacing,
        uint256 lookback,
        int32 activeTick,
        IERC20 tokenA,
        IERC20 tokenB,
        uint8 kinds,
        address accessor
    );
    event SetFactoryProtocolFeeRatio(uint8 protocolFeeRatioD3);
    event SetFactoryProtocolLendingFeeRate(uint256 lendingFeeRateD18);
    event SetFactoryProtocolFeeReceiver(address receiver);

    struct DeployParameters {
        uint64 feeAIn;
        uint64 feeBIn;
        uint32 lookback;
        int32 activeTick;
        uint64 tokenAScale;
        uint64 tokenBScale;
        // slot
        IERC20 tokenA;
        // slot
        IERC20 tokenB;
        // slot
        uint16 tickSpacing;
        uint8 options;
        address accessor;
    }

    /**
     * @notice Called by deployer library to initialize a pool.
     */
    function deployParameters()
        external
        view
        returns (
            uint64 feeAIn,
            uint64 feeBIn,
            uint32 lookback,
            int32 activeTick,
            uint64 tokenAScale,
            uint64 tokenBScale,
            // slot
            IERC20 tokenA,
            // slot
            IERC20 tokenB,
            // slot
            uint16 tickSpacing,
            uint8 options,
            address accessor
        );

    /**
     * @notice Create a new MaverickV2Pool with symmetric swap fees.
     * @param fee Fraction of the pool swap amount that is retained as an LP in
     * D18 scale.
     * @param tickSpacing Tick spacing of pool where 1.0001^tickSpacing is the
     * bin width.
     * @param lookback Pool lookback in seconds.
     * @param tokenA Address of tokenA.
     * @param tokenB Address of tokenB.
     * @param activeTick Tick position that contains the active bins.
     * @param kinds 1-15 number to represent the active kinds
     * 0b0001 = static;
     * 0b0010 = right;
     * 0b0100 = left;
     * 0b1000 = both.
     * E.g. a pool with all 4 modes will have kinds = b1111 = 15
     */
    function create(
        uint64 fee,
        uint16 tickSpacing,
        uint32 lookback,
        IERC20 tokenA,
        IERC20 tokenB,
        int32 activeTick,
        uint8 kinds
    ) external returns (IMaverickV2Pool);

    /**
     * @notice Create a new MaverickV2Pool.
     * @param feeAIn Fraction of the pool swap amount for tokenA-input swaps
     * that is retained as an LP in D18 scale.
     * @param feeBIn Fraction of the pool swap amount for tokenB-input swaps
     * that is retained as an LP in D18 scale.
     * @param tickSpacing Tick spacing of pool where 1.0001^tickSpacing is the
     * bin width.
     * @param lookback Pool lookback in seconds.
     * @param tokenA Address of tokenA.
     * @param tokenB Address of tokenB.
     * @param activeTick Tick position that contains the active bins.
     * @param kinds 1-15 number to represent the active kinds
     * 0b0001 = static;
     * 0b0010 = right;
     * 0b0100 = left;
     * 0b1000 = both.
     * e.g. a pool with all 4 modes will have kinds = b1111 = 15
     */
    function create(
        uint64 feeAIn,
        uint64 feeBIn,
        uint16 tickSpacing,
        uint32 lookback,
        IERC20 tokenA,
        IERC20 tokenB,
        int32 activeTick,
        uint8 kinds
    ) external returns (IMaverickV2Pool);

    /**
     * @notice Create a new MaverickV2PoolPermissioned with symmetric swap fees
     * with all functions permissioned.  Set fee to zero to make the pool fee settable by the accessor.
     * @param fee Fraction of the pool swap amount that is retained as an LP in
     * D18 scale.
     * @param tickSpacing Tick spacing of pool where 1.0001^tickSpacing is the
     * bin width.
     * @param lookback Pool lookback in seconds.
     * @param tokenA Address of tokenA.
     * @param tokenB Address of tokenB.
     * @param activeTick Tick position that contains the active bins.
     * @param kinds 1-15 number to represent the active kinds
     * 0b0001 = static;
     * 0b0010 = right;
     * 0b0100 = left;
     * 0b1000 = both.
     * E.g. a pool with all 4 modes will have kinds = b1111 = 15
     * @param accessor Only address that can access the pool's public write functions.
     */
    function createPermissioned(
        uint64 fee,
        uint16 tickSpacing,
        uint32 lookback,
        IERC20 tokenA,
        IERC20 tokenB,
        int32 activeTick,
        uint8 kinds,
        address accessor
    ) external returns (IMaverickV2Pool);

    /**
     * @notice Create a new MaverickV2PoolPermissioned with all functions
     * permissioned. Set fees to zero to make the pool fee settable by the
     * accessor.
     * @param feeAIn Fraction of the pool swap amount for tokenA-input swaps
     * that is retained as an LP in D18 scale.
     * @param feeBIn Fraction of the pool swap amount for tokenB-input swaps
     * that is retained as an LP in D18 scale.
     * @param tickSpacing Tick spacing of pool where 1.0001^tickSpacing is the
     * bin width.
     * @param lookback Pool lookback in seconds.
     * @param tokenA Address of tokenA.
     * @param tokenB Address of tokenB.
     * @param activeTick Tick position that contains the active bins.
     * @param kinds 1-15 number to represent the active kinds
     * 0b0001 = static;
     * 0b0010 = right;
     * 0b0100 = left;
     * 0b1000 = both.
     * E.g. a pool with all 4 modes will have kinds = b1111 = 15
     * @param accessor only address that can access the pool's public write functions.
     */
    function createPermissioned(
        uint64 feeAIn,
        uint64 feeBIn,
        uint16 tickSpacing,
        uint32 lookback,
        IERC20 tokenA,
        IERC20 tokenB,
        int32 activeTick,
        uint8 kinds,
        address accessor
    ) external returns (IMaverickV2Pool);

    /**
     * @notice Create a new MaverickV2PoolPermissioned with the option to make
     * a subset of function permissionless. Set fee to zero to make the pool
     * fee settable by the accessor.
     * @param feeAIn Fraction of the pool swap amount for tokenA-input swaps
     * that is retained as an LP in D18 scale.
     * @param feeBIn Fraction of the pool swap amount for tokenB-input swaps
     * that is retained as an LP in D18 scale.
     * @param tickSpacing Tick spacing of pool where 1.0001^tickSpacing is the
     * bin width.
     * @param lookback Pool lookback in seconds.
     * @param tokenA Address of tokenA.
     * @param tokenB Address of tokenB.
     * @param activeTick Tick position that contains the active bins.
     * @param kinds 1-15 number to represent the active kinds
     * 0b0001 = static;
     * 0b0010 = right;
     * 0b0100 = left;
     * 0b1000 = both.
     * E.g. a pool with all 4 modes will have kinds = b1111 = 15
     * @param accessor only address that can access the pool's public permissioned write functions.
     * @param  permissionedLiquidity If true, then only accessor can call
     * pool's liquidity management functions: `flashLoan`,
     * `migrateBinsUpstack`, `addLiquidity`, `removeLiquidity`.
     * @param  permissionedSwap If true, then only accessor can call
     * pool's swap function.
     */
    function createPermissioned(
        uint64 feeAIn,
        uint64 feeBIn,
        uint16 tickSpacing,
        uint32 lookback,
        IERC20 tokenA,
        IERC20 tokenB,
        int32 activeTick,
        uint8 kinds,
        address accessor,
        bool permissionedLiquidity,
        bool permissionedSwap
    ) external returns (IMaverickV2Pool pool);

    /**
     * @notice Update the protocol fee ratio for a pool. Can be called
     * permissionlessly allowing any user to sync the pool protocol fee value
     * with the factory protocol fee value.
     * @param pool The pool for which to update.
     */
    function updateProtocolFeeRatioForPool(IMaverickV2Pool pool) external;

    /**
     * @notice Update the protocol lending fee rate for a pool. Can be called
     * permissionlessly allowing any user to sync the pool protocol lending fee
     * rate value with the factory value.
     * @param pool The pool for which to update.
     */
    function updateProtocolLendingFeeRateForPool(IMaverickV2Pool pool) external;

    /**
     * @notice Claim protocol fee for a pool and transfer it to the protocolFeeReceiver.
     * @param pool The pool from which to claim the protocol fee.
     * @param isTokenA A boolean indicating whether tokenA (true) or tokenB
     * (false) is being collected.
     */
    function claimProtocolFeeForPool(IMaverickV2Pool pool, bool isTokenA) external;

    /**
     * @notice Claim protocol fee for a pool and transfer it to the protocolFeeReceiver.
     * @param pool The pool from which to claim the protocol fee.
     */
    function claimProtocolFeeForPool(IMaverickV2Pool pool) external;

    /**
     * @notice Bool indicating whether the pool was deployed from this factory.
     */
    function isFactoryPool(IMaverickV2Pool pool) external view returns (bool);

    /**
     * @notice Address that receives the protocol fee when users call
     * `claimProtocolFeeForPool`.
     */
    function protocolFeeReceiver() external view returns (address);

    /**
     * @notice Lookup a pool for given parameters.
     *
     * @dev  options bit map of kinds and function permissions
     * 0b000001 = static;
     * 0b000010 = right;
     * 0b000100 = left;
     * 0b001000 = both;
     * 0b010000 = liquidity functions are permissioned
     * 0b100000 = swap function is permissioned
     */
    function lookupPermissioned(
        uint256 feeAIn,
        uint256 feeBIn,
        uint256 tickSpacing,
        uint256 lookback,
        IERC20 tokenA,
        IERC20 tokenB,
        uint8 options,
        address accessor
    ) external view returns (IMaverickV2Pool);

    /**
     * @notice Lookup a pool for given parameters.
     */
    function lookupPermissioned(
        IERC20 _tokenA,
        IERC20 _tokenB,
        address accessor,
        uint256 startIndex,
        uint256 endIndex
    ) external view returns (IMaverickV2Pool[] memory pools);

    /**
     * @notice Lookup a pool for given parameters.
     */
    function lookupPermissioned(
        uint256 startIndex,
        uint256 endIndex
    ) external view returns (IMaverickV2Pool[] memory pools);

    /**
     * @notice Lookup a pool for given parameters.
     */
    function lookup(
        uint256 feeAIn,
        uint256 feeBIn,
        uint256 tickSpacing,
        uint256 lookback,
        IERC20 tokenA,
        IERC20 tokenB,
        uint8 kinds
    ) external view returns (IMaverickV2Pool);

    /**
     * @notice Lookup a pool for given parameters.
     */
    function lookup(
        IERC20 _tokenA,
        IERC20 _tokenB,
        uint256 startIndex,
        uint256 endIndex
    ) external view returns (IMaverickV2Pool[] memory pools);

    /**
     * @notice Lookup a pool for given parameters.
     */
    function lookup(uint256 startIndex, uint256 endIndex) external view returns (IMaverickV2Pool[] memory pools);

    /**
     * @notice Count of permissionless pools.
     */
    function poolCount() external view returns (uint256 _poolCount);

    /**
     * @notice Count of permissioned pools.
     */
    function poolPermissionedCount() external view returns (uint256 _poolCount);

    /**
     * @notice Count of pools for a given accessor and token pair.  For
     * permissionless pools, pass `accessor = address(0)`.
     */
    function poolByTokenCount(
        IERC20 _tokenA,
        IERC20 _tokenB,
        address accessor
    ) external view returns (uint256 _poolCount);

    /**
     * @notice Get the current factory owner.
     */
    function owner() external view returns (address);

    /**
     * @notice Proportion of protocol fee to collect on each swap.  Value is in
     * 3-decimal format with a maximum value of 0.25e3.
     */
    function protocolFeeRatioD3() external view returns (uint8);

    /**
     * @notice Fee rate charged by the protocol for flashloans.  Value is in
     * 18-decimal format with a maximum value of 0.02e18.
     */
    function protocolLendingFeeRateD18() external view returns (uint256);
}

File 5 of 34 : IMaverickV2Pool.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// As the copyright holder of this work, Ubiquity Labs retains
// the right to distribute, use, and modify this code under any license of
// their choosing, in addition to the terms of the GPL-v2 or later.
pragma solidity ^0.8.25;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IMaverickV2Factory} from "./IMaverickV2Factory.sol";

interface IMaverickV2Pool {
    error PoolZeroLiquidityAdded();
    error PoolMinimumLiquidityNotMet();
    error PoolLocked();
    error PoolInvalidFee();
    error PoolTicksNotSorted(uint256 index, int256 previousTick, int256 tick);
    error PoolTicksAmountsLengthMismatch(uint256 ticksLength, uint256 amountsLength);
    error PoolBinIdsAmountsLengthMismatch(uint256 binIdsLength, uint256 amountsLength);
    error PoolKindNotSupported(uint256 kinds, uint256 kind);
    error PoolInsufficientBalance(uint256 deltaLpAmount, uint256 accountBalance);
    error PoolReservesExceedMaximum(uint256 amount);
    error PoolValueExceedsBits(uint256 amount, uint256 bits);
    error PoolTickMaxExceeded(uint256 tick);
    error PoolMigrateBinFirst();
    error PoolCurrentTickBeyondSwapLimit(int32 startingTick);
    error PoolSenderNotAccessor(address sender_, address accessor);
    error PoolSenderNotFactory(address sender_, address accessor);
    error PoolFunctionNotImplemented();
    error PoolTokenNotSolvent(uint256 internalReserve, uint256 tokenBalance, IERC20 token);

    event PoolSwap(address sender, address recipient, SwapParams params, uint256 amountIn, uint256 amountOut);

    event PoolAddLiquidity(
        address sender,
        address recipient,
        uint256 subaccount,
        AddLiquidityParams params,
        uint256 tokenAAmount,
        uint256 tokenBAmount,
        uint32[] binIds
    );

    event PoolMigrateBinsUpStack(address sender, uint32 binId, uint32 maxRecursion);

    event PoolRemoveLiquidity(
        address sender,
        address recipient,
        uint256 subaccount,
        RemoveLiquidityParams params,
        uint256 tokenAOut,
        uint256 tokenBOut
    );

    event PoolSetVariableFee(uint256 newFeeAIn, uint256 newFeeBIn);

    /**
     * @notice Tick state parameters.
     */
    struct TickState {
        uint128 reserveA;
        uint128 reserveB;
        uint128 totalSupply;
        uint32[4] binIdsByTick;
    }

    /**
     * @notice Tick data parameters.
     * @param currentReserveA Current reserve of token A.
     * @param currentReserveB Current reserve of token B.
     * @param currentLiquidity Current liquidity amount.
     */
    struct TickData {
        uint256 currentReserveA;
        uint256 currentReserveB;
        uint256 currentLiquidity;
    }

    /**
     * @notice Bin state parameters.
     * @param mergeBinBalance LP token balance that this bin possesses of the merge bin.
     * @param mergeId Bin ID of the bin that this bin has merged into.
     * @param totalSupply Total amount of LP tokens in this bin.
     * @param kind One of the 4 kinds (0=static, 1=right, 2=left, 3=both).
     * @param tick The lower price tick of the bin in its current state.
     * @param tickBalance Balance of the tick.
     */
    struct BinState {
        uint128 mergeBinBalance;
        uint128 tickBalance;
        uint128 totalSupply;
        uint8 kind;
        int32 tick;
        uint32 mergeId;
    }

    /**
     * @notice Parameters for swap.
     * @param amount Amount of the token that is either the input if exactOutput is false
     * or the output if exactOutput is true.
     * @param tokenAIn Boolean indicating whether tokenA is the input.
     * @param exactOutput Boolean indicating whether the amount specified is
     * the exact output amount (true).
     * @param tickLimit The furthest tick a swap will execute in. If no limit
     * is desired, value should be set to type(int32).max for a tokenAIn swap
     * and type(int32).min for a swap where tokenB is the input.
     */
    struct SwapParams {
        uint256 amount;
        bool tokenAIn;
        bool exactOutput;
        int32 tickLimit;
    }

    /**
     * @notice Parameters associated with adding liquidity.
     * @param kind One of the 4 kinds (0=static, 1=right, 2=left, 3=both).
     * @param ticks Array of ticks to add liquidity to.
     * @param amounts Array of bin LP amounts to add.
     */
    struct AddLiquidityParams {
        uint8 kind;
        int32[] ticks;
        uint128[] amounts;
    }

    /**
     * @notice Parameters for each bin that will have liquidity removed.
     * @param binIds Index array of the bins losing liquidity.
     * @param amounts Array of bin LP amounts to remove.
     */
    struct RemoveLiquidityParams {
        uint32[] binIds;
        uint128[] amounts;
    }

    /**
     * @notice State of the pool.
     * @param reserveA Pool tokenA balanceOf at end of last operation
     * @param reserveB Pool tokenB balanceOf at end of last operation
     * @param lastTwaD8 Value of log time weighted average price at last block.
     * Value is 8-decimal scale and is in the fractional tick domain.  E.g. a
     * value of 12.3e8 indicates the TWAP was 3/10ths of the way into the 12th
     * tick.
     * @param lastLogPriceD8 Value of log price at last block. Value is
     * 8-decimal scale and is in the fractional tick domain.  E.g. a value of
     * 12.3e8 indicates the price was 3/10ths of the way into the 12th tick.
     * @param lastTimestamp Last block.timestamp value in seconds for latest
     * swap transaction.
     * @param activeTick Current tick position that contains the active bins.
     * @param isLocked Pool isLocked, E.g., locked or unlocked; isLocked values
     * defined in Pool.sol.
     * @param binCounter Index of the last bin created.
     * @param protocolFeeRatioD3 Ratio of the swap fee that is kept for the
     * protocol.
     */
    struct State {
        uint128 reserveA;
        uint128 reserveB;
        int64 lastTwaD8;
        int64 lastLogPriceD8;
        uint40 lastTimestamp;
        int32 activeTick;
        bool isLocked;
        uint32 binCounter;
        uint8 protocolFeeRatioD3;
    }

    /**
     * @notice Internal data used for data passing between Pool and Bin code.
     */
    struct BinDelta {
        uint128 deltaA;
        uint128 deltaB;
    }

    /**
     * @notice 1-15 number to represent the active kinds.
     * @notice 0b0001 = static;
     * @notice 0b0010 = right;
     * @notice 0b0100 = left;
     * @notice 0b1000 = both;
     *
     * E.g. a pool with all 4 modes will have kinds = b1111 = 15
     */
    function kinds() external view returns (uint8 _kinds);

    /**
     * @notice Returns whether a pool has permissioned functions. If true, the
     * `accessor()` of the pool can set the pool fees.  Other functions in the
     * pool may also be permissioned; whether or not they are can be determined
     * through calls to `permissionedLiquidity()` and `permissionedSwap()`.
     */
    function permissionedPool() external view returns (bool _permissionedPool);

    /**
     * @notice Returns whether a pool has permissioned liquidity management
     * functions. If true, the pool is incompatible with permissioned pool
     * liquidity management infrastructure.
     */
    function permissionedLiquidity() external view returns (bool _permissionedLiquidity);

    /**
     * @notice Returns whether a pool has a permissioned swap functions. If
     * true, the pool is incompatible with permissioned pool swap router
     * infrastructure.
     */
    function permissionedSwap() external view returns (bool _permissionedSwap);

    /**
     * @notice Pool swap fee for the given direction (A-in or B-in swap) in
     * 18-decimal format. E.g. 0.01e18 is a 1% swap fee.
     */
    function fee(bool tokenAIn) external view returns (uint256);

    /**
     * @notice TickSpacing of pool where 1.0001^tickSpacing is the bin width.
     */
    function tickSpacing() external view returns (uint256);

    /**
     * @notice Lookback period of pool in seconds.
     */
    function lookback() external view returns (uint256);

    /**
     * @notice Address of Pool accessor.  This is Zero address for
     * permissionless pools.
     */
    function accessor() external view returns (address);

    /**
     * @notice Pool tokenA.  Address of tokenA is such that tokenA < tokenB.
     */
    function tokenA() external view returns (IERC20);

    /**
     * @notice Pool tokenB.
     */
    function tokenB() external view returns (IERC20);

    /**
     * @notice Deploying factory of the pool and also contract that has ability
     * to set and collect protocol fees for the pool.
     */
    function factory() external view returns (IMaverickV2Factory);

    /**
     * @notice Most significant bit of scale value is a flag to indicate whether
     * tokenA has more or less than 18 decimals.  Scale is used in conjuction
     * with Math.toScale/Math.fromScale functions to convert from token amounts
     * to D18 scale internal pool accounting.
     */
    function tokenAScale() external view returns (uint256);

    /**
     * @notice Most significant bit of scale value is a flag to indicate whether
     * tokenA has more or less than 18 decimals.  Scale is used in conjuction
     * with Math.toScale/Math.fromScale functions to convert from token amounts
     * to D18 scale internal pool accounting.
     */
    function tokenBScale() external view returns (uint256);

    /**
     * @notice ID of bin at input tick position and kind.
     */
    function binIdByTickKind(int32 tick, uint256 kind) external view returns (uint32);

    /**
     * @notice Accumulated tokenA protocol fee.
     */
    function protocolFeeA() external view returns (uint128);

    /**
     * @notice Accumulated tokenB protocol fee.
     */
    function protocolFeeB() external view returns (uint128);

    /**
     * @notice Lending fee rate on flash loans.
     */
    function lendingFeeRateD18() external view returns (uint256);

    /**
     * @notice External function to get the current time-weighted average price.
     */
    function getCurrentTwa() external view returns (int256);

    /**
     * @notice External function to get the state of the pool.
     */
    function getState() external view returns (State memory);

    /**
     * @notice Return state of Bin at input binId.
     */
    function getBin(uint32 binId) external view returns (BinState memory bin);

    /**
     * @notice Return state of Tick at input tick position.
     */
    function getTick(int32 tick) external view returns (TickState memory tickState);

    /**
     * @notice Retrieves the balance of a user within a bin.
     * @param user The user's address.
     * @param subaccount The subaccount for the user.
     * @param binId The ID of the bin.
     */
    function balanceOf(address user, uint256 subaccount, uint32 binId) external view returns (uint128 lpToken);

    /**
     * @notice Add liquidity to a pool. This function allows users to deposit
     * tokens into a liquidity pool.
     * @dev This function will call `maverickV2AddLiquidityCallback` on the
     * calling contract to collect the tokenA/tokenB payment.
     * @param recipient The account that will receive credit for the added liquidity.
     * @param subaccount The account that will receive credit for the added liquidity.
     * @param params Parameters containing the details for adding liquidity,
     * such as token types and amounts.
     * @param data Bytes information that gets passed to the callback.
     * @return tokenAAmount The amount of token A added to the pool.
     * @return tokenBAmount The amount of token B added to the pool.
     * @return binIds An array of bin IDs where the liquidity is stored.
     */
    function addLiquidity(
        address recipient,
        uint256 subaccount,
        AddLiquidityParams calldata params,
        bytes calldata data
    ) external returns (uint256 tokenAAmount, uint256 tokenBAmount, uint32[] memory binIds);

    /**
     * @notice Removes liquidity from the pool.
     * @dev Liquidy can only be removed from a bin that is either unmerged or
     * has a mergeId of an unmerged bin.  If a bin is merged more than one
     * level deep, it must be migrated up the merge stack to the root bin
     * before liquidity removal.
     * @param recipient The address to receive the tokens.
     * @param subaccount The subaccount for the recipient.
     * @param params The parameters for removing liquidity.
     * @return tokenAOut The amount of token A received.
     * @return tokenBOut The amount of token B received.
     */
    function removeLiquidity(
        address recipient,
        uint256 subaccount,
        RemoveLiquidityParams calldata params
    ) external returns (uint256 tokenAOut, uint256 tokenBOut);

    /**
     * @notice Migrate bins up the linked list of merged bins so that its
     * mergeId is the currrent active bin.
     * @dev Liquidy can only be removed from a bin that is either unmerged or
     * has a mergeId of an unmerged bin.  If a bin is merged more than one
     * level deep, it must be migrated up the merge stack to the root bin
     * before liquidity removal.
     * @param binId The ID of the bin to migrate.
     * @param maxRecursion The maximum recursion depth for the migration.
     */
    function migrateBinUpStack(uint32 binId, uint32 maxRecursion) external;

    /**
     * @notice Swap tokenA/tokenB assets in the pool.  The swap user has two
     * options for funding their swap.
     * - The user can push the input token amount to the pool before calling
     * the swap function. In order to avoid having the pool call the callback,
     * the user should pass a zero-length `data` bytes object with the swap
     * call.
     * - The user can send the input token amount to the pool when the pool
     * calls the `maverickV2SwapCallback` function on the calling contract.
     * That callback has input parameters that specify the token address of the
     * input token, the input and output amounts, and the bytes data sent to
     * the swap function.
     * @dev  If the users elects to do a callback-based swap, the output
     * assets will be sent before the callback is called, allowing the user to
     * execute flash swaps.  However, the pool does have reentrancy protection,
     * so a swapper will not be able to interact with the same pool again
     * while they are in the callback function.
     * @param recipient The address to receive the output tokens.
     * @param params Parameters containing the details of the swap
     * @param data Bytes information that gets passed to the callback.
     */
    function swap(
        address recipient,
        SwapParams memory params,
        bytes calldata data
    ) external returns (uint256 amountIn, uint256 amountOut);

    /**
     * @notice Loan tokenA/tokenB assets from the pool to recipient. The fee
     * rate of a loan is determined by `lendingFeeRateD18`, which is set at the
     * protocol level by the factory.  This function calls
     * `maverickV2FlashLoanCallback` on the calling contract.  At the end of
     * the callback, the caller must pay back the loan with fee (if there is a
     * fee).
     * @param recipient The address to receive the loaned tokens.
     * @param amountB Loan amount of tokenA sent to recipient.
     * @param amountB Loan amount of tokenB sent to recipient.
     * @param data Bytes information that gets passed to the callback.
     */
    function flashLoan(
        address recipient,
        uint256 amountA,
        uint256 amountB,
        bytes calldata data
    ) external returns (uint128 lendingFeeA, uint128 lendingFeeB);

    /**
     * @notice Sets fee for permissioned pools.  May only be called by the
     * accessor.
     */
    function setFee(uint256 newFeeAIn, uint256 newFeeBIn) external;
}

File 6 of 34 : Constants.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// As the copyright holder of this work, Ubiquity Labs retains
// the right to distribute, use, and modify this code under any license of
// their choosing, in addition to the terms of the GPL-v2 or later.
pragma solidity ^0.8.25;

// factory contraints on pools
uint8 constant MAX_PROTOCOL_FEE_RATIO_D3 = 0.25e3; // 25%
uint256 constant MAX_PROTOCOL_LENDING_FEE_RATE_D18 = 0.02e18; // 2%
uint64 constant MAX_POOL_FEE_D18 = 0.9e18; // 90%
uint64 constant MIN_LOOKBACK = 1 seconds;
uint64 constant MAX_TICK_SPACING = 10_000;

// pool constraints
uint8 constant NUMBER_OF_KINDS = 4;
int32 constant NUMBER_OF_KINDS_32 = int32(int8(NUMBER_OF_KINDS));
uint256 constant MAX_TICK = 322_378; // max price 1e14 in D18 scale
int32 constant MAX_TICK_32 = int32(int256(MAX_TICK));
int32 constant MIN_TICK_32 = int32(-int256(MAX_TICK));
uint256 constant MAX_BINS_TO_MERGE = 3;
uint128 constant MINIMUM_LIQUIDITY = 1e8;

// accessor named constants
uint8 constant ALL_KINDS_MASK = 0xF; // 0b1111
uint8 constant PERMISSIONED_LIQUIDITY_MASK = 0x10; // 0b010000
uint8 constant PERMISSIONED_SWAP_MASK = 0x20; // 0b100000
uint8 constant OPTIONS_MASK = ALL_KINDS_MASK | PERMISSIONED_LIQUIDITY_MASK | PERMISSIONED_SWAP_MASK; // 0b111111

// named values
address constant MERGED_LP_BALANCE_ADDRESS = address(0);
uint256 constant MERGED_LP_BALANCE_SUBACCOUNT = 0;
uint128 constant ONE = 1e18;
uint128 constant ONE_SQUARED = 1e36;
int256 constant INT256_ONE = 1e18;
uint256 constant ONE_D8 = 1e8;
uint256 constant ONE_D3 = 1e3;
int40 constant INT_ONE_D8 = 1e8;
int40 constant HALF_TICK_D8 = 0.5e8;
uint8 constant DEFAULT_DECIMALS = 18;
uint256 constant DEFAULT_SCALE = 1;
bytes constant EMPTY_PRICE_BREAKS = hex"010000000000000000000000";

File 7 of 34 : Math.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// As the copyright holder of this work, Ubiquity Labs retains
// the right to distribute, use, and modify this code under any license of
// their choosing, in addition to the terms of the GPL-v2 or later.
pragma solidity ^0.8.25;

import {Math as OzMath} from "@openzeppelin/contracts/utils/math/Math.sol";

import {ONE, DEFAULT_SCALE, DEFAULT_DECIMALS, INT_ONE_D8, ONE_SQUARED} from "./Constants.sol";

/**
 * @notice Math functions.
 */
library Math {
    /**
     * @notice Returns the lesser of two values.
     * @param x First uint256 value.
     * @param y Second uint256 value.
     */
    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly ("memory-safe") {
            z := xor(x, mul(xor(x, y), lt(y, x)))
        }
    }

    /**
     * @notice Returns the lesser of two uint128 values.
     * @param x First uint128 value.
     * @param y Second uint128 value.
     */
    function min128(uint128 x, uint128 y) internal pure returns (uint128 z) {
        assembly ("memory-safe") {
            z := xor(x, mul(xor(x, y), lt(y, x)))
        }
    }

    /**
     * @notice Returns the lesser of two int256 values.
     * @param x First int256 value.
     * @param y Second int256 value.
     */
    function min(int256 x, int256 y) internal pure returns (int256 z) {
        assembly ("memory-safe") {
            z := xor(x, mul(xor(x, y), slt(y, x)))
        }
    }

    /**
     * @notice Returns the greater of two uint256 values.
     * @param x First uint256 value.
     * @param y Second uint256 value.
     */
    function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly ("memory-safe") {
            z := xor(x, mul(xor(x, y), gt(y, x)))
        }
    }

    /**
     * @notice Returns the greater of two int256 values.
     * @param x First int256 value.
     * @param y Second int256 value.
     */
    function max(int256 x, int256 y) internal pure returns (int256 z) {
        assembly ("memory-safe") {
            z := xor(x, mul(xor(x, y), sgt(y, x)))
        }
    }

    /**
     * @notice Returns the greater of two uint128 values.
     * @param x First uint128 value.
     * @param y Second uint128 value.
     */
    function max128(uint128 x, uint128 y) internal pure returns (uint128 z) {
        assembly ("memory-safe") {
            z := xor(x, mul(xor(x, y), gt(y, x)))
        }
    }

    /**
     * @notice Thresholds a value to be within the specified bounds.
     * @param value The value to bound.
     * @param lowerLimit The minimum allowable value.
     * @param upperLimit The maximum allowable value.
     */
    function boundValue(
        uint256 value,
        uint256 lowerLimit,
        uint256 upperLimit
    ) internal pure returns (uint256 outputValue) {
        outputValue = min(max(value, lowerLimit), upperLimit);
    }

    /**
     * @notice Returns the difference between two uint128 values or zero if the result would be negative.
     * @param x The minuend.
     * @param y The subtrahend.
     */
    function clip128(uint128 x, uint128 y) internal pure returns (uint128) {
        unchecked {
            return x < y ? 0 : x - y;
        }
    }

    /**
     * @notice Returns the difference between two uint256 values or zero if the result would be negative.
     * @param x The minuend.
     * @param y The subtrahend.
     */
    function clip(uint256 x, uint256 y) internal pure returns (uint256) {
        unchecked {
            return x < y ? 0 : x - y;
        }
    }

    /**
     * @notice Divides one uint256 by another, rounding down to the nearest
     * integer.
     * @param x The dividend.
     * @param y The divisor.
     */
    function divFloor(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivFloor(x, ONE, y);
    }

    /**
     * @notice Divides one uint256 by another, rounding up to the nearest integer.
     * @param x The dividend.
     * @param y The divisor.
     */
    function divCeil(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivCeil(x, ONE, y);
    }

    /**
     * @notice Multiplies two uint256 values and then divides by ONE, rounding down.
     * @param x The multiplicand.
     * @param y The multiplier.
     */
    function mulFloor(uint256 x, uint256 y) internal pure returns (uint256) {
        return OzMath.mulDiv(x, y, ONE);
    }

    /**
     * @notice Multiplies two uint256 values and then divides by ONE, rounding up.
     * @param x The multiplicand.
     * @param y The multiplier.
     */
    function mulCeil(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivCeil(x, y, ONE);
    }

    /**
     * @notice Calculates the multiplicative inverse of a uint256, rounding down.
     * @param x The value to invert.
     */
    function invFloor(uint256 x) internal pure returns (uint256) {
        unchecked {
            return ONE_SQUARED / x;
        }
    }

    /**
     * @notice Calculates the multiplicative inverse of a uint256, rounding up.
     * @param denominator The value to invert.
     */
    function invCeil(uint256 denominator) internal pure returns (uint256 z) {
        assembly ("memory-safe") {
            // divide z - 1 by the denominator and add 1.
            z := add(div(sub(ONE_SQUARED, 1), denominator), 1)
        }
    }

    /**
     * @notice Multiplies two uint256 values and divides by a third, rounding down.
     * @param x The multiplicand.
     * @param y The multiplier.
     * @param k The divisor.
     */
    function mulDivFloor(uint256 x, uint256 y, uint256 k) internal pure returns (uint256 result) {
        result = OzMath.mulDiv(x, y, max(1, k));
    }

    /**
     * @notice Multiplies two uint256 values and divides by a third, rounding up if there's a remainder.
     * @param x The multiplicand.
     * @param y The multiplier.
     * @param k The divisor.
     */
    function mulDivCeil(uint256 x, uint256 y, uint256 k) internal pure returns (uint256 result) {
        result = mulDivFloor(x, y, k);
        if (mulmod(x, y, max(1, k)) != 0) result = result + 1;
    }

    /**
     * @notice Multiplies two uint256 values and divides by a third, rounding
     * down. Will revert if `x * y` is larger than `type(uint256).max`.
     * @param x The first operand for multiplication.
     * @param y The second operand for multiplication.
     * @param denominator The divisor after multiplication.
     */
    function mulDivDown(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 z) {
        assembly ("memory-safe") {
            // Store x * y in z for now.
            z := mul(x, y)
            if iszero(denominator) {
                denominator := 1
            }

            if iszero(or(iszero(x), eq(div(z, x), y))) {
                revert(0, 0)
            }

            // Divide z by the denominator.
            z := div(z, denominator)
        }
    }

    /**
     * @notice Multiplies two uint256 values and divides by a third, rounding
     * up. Will revert if `x * y` is larger than `type(uint256).max`.
     * @param x The first operand for multiplication.
     * @param y The second operand for multiplication.
     * @param denominator The divisor after multiplication.
     */
    function mulDivUp(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 z) {
        assembly ("memory-safe") {
            // Store x * y in z for now.
            z := mul(x, y)
            if iszero(denominator) {
                denominator := 1
            }

            if iszero(or(iszero(x), eq(div(z, x), y))) {
                revert(0, 0)
            }

            // First, divide z - 1 by the denominator and add 1.
            // We allow z - 1 to underflow if z is 0, because we multiply the
            // end result by 0 if z is zero, ensuring we return 0 if z is zero.
            z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
        }
    }

    /**
     * @notice Multiplies a uint256 by another and divides by a constant,
     * rounding down. Will revert if `x * y` is larger than
     * `type(uint256).max`.
     * @param x The multiplicand.
     * @param y The multiplier.
     */
    function mulDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, y, ONE);
    }

    /**
     * @notice Divides a uint256 by another, rounding down the result. Will
     * revert if `x * 1e18` is larger than `type(uint256).max`.
     * @param x The dividend.
     * @param y The divisor.
     */
    function divDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, ONE, y);
    }

    /**
     * @notice Divides a uint256 by another, rounding up the result. Will
     * revert if `x * 1e18` is larger than `type(uint256).max`.
     * @param x The dividend.
     * @param y The divisor.
     */
    function divUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, ONE, y);
    }

    /**
     * @notice Scales a number based on a difference in decimals from a default.
     * @param decimals The new decimal precision.
     */
    function scale(uint8 decimals) internal pure returns (uint256) {
        unchecked {
            if (decimals == DEFAULT_DECIMALS) {
                return DEFAULT_SCALE;
            } else {
                return 10 ** (DEFAULT_DECIMALS - decimals);
            }
        }
    }

    /**
     * @notice Adjusts a scaled amount to the token decimal scale.
     * @param amount The scaled amount.
     * @param scaleFactor The scaling factor to adjust by.
     * @param ceil Whether to round up (true) or down (false).
     */
    function ammScaleToTokenScale(uint256 amount, uint256 scaleFactor, bool ceil) internal pure returns (uint256 z) {
        unchecked {
            if (scaleFactor == DEFAULT_SCALE || amount == 0) {
                return amount;
            } else {
                if (!ceil) return amount / scaleFactor;
                assembly ("memory-safe") {
                    z := add(div(sub(amount, 1), scaleFactor), 1)
                }
            }
        }
    }

    /**
     * @notice Adjusts a token amount to the D18 AMM scale.
     * @param amount The amount in token scale.
     * @param scaleFactor The scale factor for adjustment.
     */
    function tokenScaleToAmmScale(uint256 amount, uint256 scaleFactor) internal pure returns (uint256) {
        if (scaleFactor == DEFAULT_SCALE) {
            return amount;
        } else {
            return amount * scaleFactor;
        }
    }

    /**
     * @notice Returns the absolute value of a signed 32-bit integer.
     * @param x The integer to take the absolute value of.
     */
    function abs32(int32 x) internal pure returns (uint32) {
        unchecked {
            return uint32(x < 0 ? -x : x);
        }
    }

    /**
     * @notice Returns the absolute value of a signed 256-bit integer.
     * @param x The integer to take the absolute value of.
     */
    function abs(int256 x) internal pure returns (uint256) {
        unchecked {
            return uint256(x < 0 ? -x : x);
        }
    }

    /**
     * @notice Calculates the integer square root of a uint256 rounded down.
     * @param x The number to take the square root of.
     */
    function sqrt(uint256 x) internal pure returns (uint256 z) {
        // from https://github.com/transmissions11/solmate/blob/e8f96f25d48fe702117ce76c79228ca4f20206cb/src/utils/FixedPointMathLib.sol
        assembly ("memory-safe") {
            let y := x
            z := 181

            if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                y := shr(128, y)
                z := shl(64, z)
            }
            if iszero(lt(y, 0x1000000000000000000)) {
                y := shr(64, y)
                z := shl(32, z)
            }
            if iszero(lt(y, 0x10000000000)) {
                y := shr(32, y)
                z := shl(16, z)
            }
            if iszero(lt(y, 0x1000000)) {
                y := shr(16, y)
                z := shl(8, z)
            }

            z := shr(18, mul(z, add(y, 65536)))

            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            z := sub(z, lt(div(x, z), z))
        }
    }

    /**
     * @notice Computes the floor of a D8-scaled number as an int32, ignoring
     * potential overflow in the cast.
     * @param val The D8-scaled number.
     */
    function floorD8Unchecked(int256 val) internal pure returns (int32) {
        int32 val32;
        bool check;
        unchecked {
            val32 = int32(val / INT_ONE_D8);
            check = (val < 0 && val % INT_ONE_D8 != 0);
        }
        return check ? val32 - 1 : val32;
    }
}

File 8 of 34 : PoolLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// As the copyright holder of this work, Ubiquity Labs retains
// the right to distribute, use, and modify this code under any license of
// their choosing, in addition to the terms of the GPL-v2 or later.
pragma solidity ^0.8.25;

import {SafeCast as Cast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {IMaverickV2Pool} from "../interfaces/IMaverickV2Pool.sol";
import {TickMath} from "./TickMath.sol";
import {Math} from "./Math.sol";

/**
 * @notice Library of pool functions.
 */
library PoolLib {
    using Cast for uint256;

    struct AddLiquidityInfo {
        uint256 deltaA;
        uint256 deltaB;
        bool tickLtActive;
        uint256 tickSpacing;
        int32 tick;
    }

    /**
     * @notice Check to ensure that the ticks are in ascending order and amount
     * array is same length as tick array.
     * @param ticks An array of int32 values representing ticks to be checked.
     * @param amountsLength Amount array length.
     */
    function uniqueOrderedTicksCheck(int32[] memory ticks, uint256 amountsLength) internal pure {
        unchecked {
            if (ticks.length != amountsLength)
                revert IMaverickV2Pool.PoolTicksAmountsLengthMismatch(ticks.length, amountsLength);
            int32 lastTick = type(int32).min;
            for (uint256 i; i < ticks.length; ) {
                if (ticks[i] <= lastTick) revert IMaverickV2Pool.PoolTicksNotSorted(i, lastTick, ticks[i]);
                lastTick = ticks[i];
                i = i + 1;
            }
        }
    }

    /**
     * @notice Compute bin reserves assuming the bin is not merged; not accurate
     * reflection of reserves for merged bins.
     * @param bin The storage reference to the state for this bin.
     * @param tick The memory reference to the state for this tick.
     * @return reserveA The reserve amount for token A.
     * @return reserveB The reserve amount for token B.
     */
    function binReserves(
        IMaverickV2Pool.BinState storage bin,
        IMaverickV2Pool.TickState memory tick
    ) internal view returns (uint128 reserveA, uint128 reserveB) {
        return binReserves(bin.tickBalance, tick.reserveA, tick.reserveB, tick.totalSupply);
    }

    /**
     * @notice Compute bin reserves assuming the bin is not merged; not accurate
     * reflection of reserves for merged bins.
     * @param tickBalance Bin's balance in the tick.
     * @param tickReserveA Tick's tokenA reserves.
     * @param tickReserveB Tick's tokenB reserves.
     * @param tickTotalSupply Tick total supply of bin balances.
     */
    function binReserves(
        uint128 tickBalance,
        uint128 tickReserveA,
        uint128 tickReserveB,
        uint128 tickTotalSupply
    ) internal pure returns (uint128 reserveA, uint128 reserveB) {
        if (tickTotalSupply != 0) {
            reserveA = reserveValue(tickReserveA, tickBalance, tickTotalSupply);
            reserveB = reserveValue(tickReserveB, tickBalance, tickTotalSupply);
        }
    }

    /**
     * @notice Reserves of a bin in a tick.
     * @param tickReserve Tick reserve amount in a given token.
     * @param tickBalance Bin's balance in the tick.
     * @param tickTotalSupply Tick total supply of bin balances.
     */
    function reserveValue(
        uint128 tickReserve,
        uint128 tickBalance,
        uint128 tickTotalSupply
    ) internal pure returns (uint128 reserve) {
        reserve = Math.mulDivFloor(tickReserve, tickBalance, tickTotalSupply).toUint128();
        reserve = Math.min128(tickReserve, reserve);
    }

    /**
     * @notice Calculate delta A, delta B, and delta Tick Balance based on delta
     * LP balance and the Tick/Bin state.
     */
    function deltaTickBalanceFromDeltaLpBalance(
        uint256 binTickBalance,
        uint256 binTotalSupply,
        IMaverickV2Pool.TickState memory tickState,
        uint128 deltaLpBalance,
        AddLiquidityInfo memory addLiquidityInfo
    ) internal pure returns (uint256 deltaTickBalance) {
        unchecked {
            if (tickState.reserveA != 0 || tickState.reserveB != 0) {
                // if there are already reserves, then we just contribute pro rata
                // deltaLiquidity = deltaBinLP / binTS * binTickBalance / tickTS * tickL
                uint256 numerator = Math.max(1, binTickBalance) * uint256(deltaLpBalance);
                uint256 denominator = Math.max(1, tickState.totalSupply) * Math.max(1, binTotalSupply);
                addLiquidityInfo.deltaA = Math.mulDivCeil(tickState.reserveA, numerator, denominator);
                addLiquidityInfo.deltaB = Math.mulDivCeil(tickState.reserveB, numerator, denominator);
            } else {
                _setRequiredDeltaReservesForEmptyTick(deltaLpBalance, addLiquidityInfo);
            }

            // round down the amount credited to the tick; this could lead to a
            // small add amount getting zero reserves credit.
            deltaTickBalance = tickState.totalSupply == 0
                ? deltaLpBalance
                : Math.mulDivDown(deltaLpBalance, Math.max(1, binTickBalance), binTotalSupply);
        }
    }

    /**
     * @notice Calculates deltaA = liquidity * (sqrt(upper) - sqrt(lower))
     * @notice Calculates deltaB = liquidity / sqrt(lower) - liquidity / sqrt(upper),
     * @notice i.e. liquidity * (sqrt(upper) - sqrt(lower)) / (sqrt(upper) * sqrt(lower))
     * @notice we set liquidity = deltaLpBalance / (1.0001^(tick * tickspacing) - 1)
     * @notice which simplifies the A/B amounts to:
     * @notice deltaA = deltaLpBalance * sqrt(lower)
     * @notice deltaB = deltaLpBalance / sqrt(upper)
     */
    function _setRequiredDeltaReservesForEmptyTick(
        uint128 deltaLpBalance,
        AddLiquidityInfo memory addLiquidityInfo
    ) internal pure {
        // No reserves, so we will use deltaLpBalance as liquidity to be added.
        // In this logic branch, the tick is empty, so we know the tick will be
        // a one-asset add.
        (uint256 sqrtLowerTickPrice, uint256 sqrtUpperTickPrice) = TickMath.tickSqrtPrices(
            addLiquidityInfo.tickSpacing,
            addLiquidityInfo.tick
        );

        addLiquidityInfo.deltaA = addLiquidityInfo.tickLtActive ? Math.mulCeil(deltaLpBalance, sqrtLowerTickPrice) : 0;
        addLiquidityInfo.deltaB = addLiquidityInfo.tickLtActive ? 0 : Math.divCeil(deltaLpBalance, sqrtUpperTickPrice);
    }
}

File 9 of 34 : TickMath.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// As the copyright holder of this work, Ubiquity Labs retains
// the right to distribute, use, and modify this code under any license of
// their choosing, in addition to the terms of the GPL-v2 or later.
pragma solidity ^0.8.25;

import {Math as OzMath} from "@openzeppelin/contracts/utils/math/Math.sol";
import {Math} from "./Math.sol";
import {MAX_TICK, ONE} from "./Constants.sol";

/**
 * @notice Math functions related to tick operations.
 */
library TickMath {
    using Math for uint256;

    error TickMaxExceeded(int256 tick);

    /**
     * @notice Compute the lower and upper sqrtPrice of a tick.
     * @param tickSpacing The tick spacing used for calculations.
     * @param _tick The input tick value.
     */
    function tickSqrtPrices(
        uint256 tickSpacing,
        int32 _tick
    ) internal pure returns (uint256 sqrtLowerPrice, uint256 sqrtUpperPrice) {
        unchecked {
            sqrtLowerPrice = tickSqrtPrice(tickSpacing, _tick);
            sqrtUpperPrice = tickSqrtPrice(tickSpacing, _tick + 1);
        }
    }

    /**
     * @notice Compute the base tick value from the pool tick and the
     * tickSpacing.  Revert if base tick is beyond the max tick boundary.
     * @param tickSpacing The tick spacing used for calculations.
     * @param _tick The input tick value.
     */
    function subTickIndex(uint256 tickSpacing, int32 _tick) internal pure returns (uint32 subTick) {
        subTick = Math.abs32(_tick);
        subTick *= uint32(tickSpacing);
        if (subTick > MAX_TICK) {
            revert TickMaxExceeded(_tick);
        }
    }

    /**
     * @notice Calculate the square root price for a given tick and tick spacing.
     * @param tickSpacing The tick spacing used for calculations.
     * @param _tick The input tick value.
     * @return _result The square root price.
     */
    function tickSqrtPrice(uint256 tickSpacing, int32 _tick) internal pure returns (uint256 _result) {
        unchecked {
            uint256 tick = subTickIndex(tickSpacing, _tick);

            uint256 ratio = tick & 0x1 != 0 ? 0xfffcb933bd6fad9d3af5f0b9f25db4d6 : 0x100000000000000000000000000000000;
            if (tick & 0x2 != 0) ratio = (ratio * 0xfff97272373d41fd789c8cb37ffcaa1c) >> 128;
            if (tick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656ac9229c67059486f389) >> 128;
            if (tick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e81259b3cddc7a064941) >> 128;
            if (tick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f67b19e8887e0bd251eb7) >> 128;
            if (tick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98cd2e57b660be99eb2c4a) >> 128;
            if (tick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c9838804e327cb417cafcb) >> 128;
            if (tick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99d51e2cc356c2f617dbe0) >> 128;
            if (tick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900aecf64236ab31f1f9dcb5) >> 128;
            if (tick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac4d9194200696907cf2e37) >> 128;
            if (tick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b88206f8abe8a3b44dd9be) >> 128;
            if (tick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c578ef4f1d17b2b235d480) >> 128;
            if (tick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd254ee83bdd3f248e7e785e) >> 128;
            if (tick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d8f7dd10e744d913d033333) >> 128;
            if (tick & 0x4000 != 0) ratio = (ratio * 0x70d869a156ddd32a39e257bc3f50aa9b) >> 128;
            if (tick & 0x8000 != 0) ratio = (ratio * 0x31be135f97da6e09a19dc367e3b6da40) >> 128;
            if (tick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7e5a9780b0cc4e25d61a56) >> 128;
            if (tick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedbcb3a6ccb7ce618d14225) >> 128;
            if (tick & 0x40000 != 0) ratio = (ratio * 0x2216e584f630389b2052b8db590e) >> 128;
            if (_tick > 0) ratio = type(uint256).max / ratio;
            _result = (ratio * ONE) >> 128;
        }
    }

    /**
     * @notice Calculate liquidity of a tick.
     * @param reserveA Tick reserve of token A.
     * @param reserveB Tick reserve of token B.
     * @param sqrtLowerTickPrice The square root price of the lower tick edge.
     * @param sqrtUpperTickPrice The square root price of the upper tick edge.
     */
    function getTickL(
        uint256 reserveA,
        uint256 reserveB,
        uint256 sqrtLowerTickPrice,
        uint256 sqrtUpperTickPrice
    ) internal pure returns (uint256 liquidity) {
        // known:
        // - sqrt price values are different
        // - reserveA and reserveB fit in 128 bit
        // - sqrt price is in (1e-7, 1e7)
        // - D18 max for uint256 is 1.15e59
        // - D18 min is 1e-18

        unchecked {
            // diff is in (5e-12, 4e6); max tick spacing is 10_000
            uint256 diff = sqrtUpperTickPrice - sqrtLowerTickPrice;

            // Need to maximize precision by shifting small values A and B up so
            // that they use more of the available bit range. Two constraints to
            // consider: we need A * B * diff / sqrtPrice to be bigger than 1e-18
            // when the bump is not in play.  This constrains the threshold for
            // bumping to be at least 77 bit; ie, either a or b needs 2^77 which
            // means that term A * B * diff / sqrtPrice > 1e-18.
            //
            // At the other end, the second constraint is that b^2 needs to fit in
            // a 256-bit number, so, post bump, the max reserve value needs to be
            // less than 6e22. With a 78-bit threshold and a 57-bit bump, we have A
            // and B are in (1.4e-1, 4.4e22 (2^(78+57))) with bump, and one of A or
            // B is at least 2^78 without the bump, but the other reserve value may
            // be as small as 1 wei.
            uint256 precisionBump = 0;
            if ((reserveA >> 78) == 0 && (reserveB >> 78) == 0) {
                precisionBump = 57;
                reserveA <<= precisionBump;
                reserveB <<= precisionBump;
            }

            if (reserveB == 0) return Math.divDown(reserveA, diff) >> precisionBump;
            if (reserveA == 0)
                return Math.mulDivDown(reserveB.mulDown(sqrtLowerTickPrice), sqrtUpperTickPrice, diff) >> precisionBump;

            // b is in (7.2e-9 (2^57 / 1e7 / 2), 2.8e29  (2^(78+57) * 1e7 / 2)) with bump
            // b is in a subset of the same range without bump
            uint256 b = (reserveA.divDown(sqrtUpperTickPrice) + reserveB.mulDown(sqrtLowerTickPrice)) >> 1;

            // b^2 is in (5.1e-17, 4.8e58); and will not overflow on either end;
            // A*B is in (3e-13 (2^78 / 1e18 * 1e-18), 1.9e45) without bump and is in a subset range with bump
            // A*B*diff/sqrtUpper is in (1.5e-17 (3e-13 * 5e-12 * 1e7), 7.6e58);

            // Since b^2 is at the upper edge of the precision range, we are not
            // able to multiply the argument of the sqrt by 1e18, instead, we move
            // this factor outside of the sqrt. The resulting loss of precision
            // means that this liquidity value is a lower bound on the tick
            // liquidity
            return
                OzMath.mulDiv(
                    b +
                        Math.sqrt(
                            (OzMath.mulDiv(b, b, ONE) +
                                OzMath.mulDiv(reserveB.mulFloor(reserveA), diff, sqrtUpperTickPrice))
                        ) *
                        1e9,
                    sqrtUpperTickPrice,
                    diff
                ) >> precisionBump;
        }
    }

    /**
     * @notice Calculate square root price of a tick. Returns left edge of the
     * tick if the tick has no reserves.
     * @param reserveA Tick reserve of token A.
     * @param reserveB Tick reserve of token B.
     * @param sqrtLowerTickPrice The square root price of the lower tick edge.
     * @param sqrtUpperTickPrice The square root price of the upper tick edge.
     * @return sqrtPrice The calculated square root price.
     */
    function getSqrtPrice(
        uint256 reserveA,
        uint256 reserveB,
        uint256 sqrtLowerTickPrice,
        uint256 sqrtUpperTickPrice,
        uint256 liquidity
    ) internal pure returns (uint256 sqrtPrice) {
        unchecked {
            if (reserveA == 0) {
                return sqrtLowerTickPrice;
            }
            if (reserveB == 0) {
                return sqrtUpperTickPrice;
            }
            sqrtPrice = Math.sqrt(
                ONE *
                    (reserveA + liquidity.mulDown(sqrtLowerTickPrice)).divDown(
                        reserveB + liquidity.divDown(sqrtUpperTickPrice)
                    )
            );
            sqrtPrice = Math.boundValue(sqrtPrice, sqrtLowerTickPrice, sqrtUpperTickPrice);
        }
    }

    /**
     * @notice Calculate square root price of a tick. Returns left edge of the
     * tick if the tick has no reserves.
     * @param reserveA Tick reserve of token A.
     * @param reserveB Tick reserve of token B.
     * @param sqrtLowerTickPrice The square root price of the lower tick edge.
     * @param sqrtUpperTickPrice The square root price of the upper tick edge.
     * @return sqrtPrice The calculated square root price.
     * @return liquidity The calculated liquidity.
     */
    function getTickSqrtPriceAndL(
        uint256 reserveA,
        uint256 reserveB,
        uint256 sqrtLowerTickPrice,
        uint256 sqrtUpperTickPrice
    ) internal pure returns (uint256 sqrtPrice, uint256 liquidity) {
        liquidity = getTickL(reserveA, reserveB, sqrtLowerTickPrice, sqrtUpperTickPrice);
        sqrtPrice = getSqrtPrice(reserveA, reserveB, sqrtLowerTickPrice, sqrtUpperTickPrice, liquidity);
    }
}

File 10 of 34 : TransferLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// As the copyright holder of this work, Ubiquity Labs retains
// the right to distribute, use, and modify this code under any license of
// their choosing, in addition to the terms of the GPL-v2 or later.
pragma solidity ^0.8.25;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @notice Low-gas transfer functions.
 */
library TransferLib {
    error TransferFailed(IERC20 token, address to, uint256 amount);
    error TransferFromFailed(IERC20 token, address from, address to, uint256 amount);

    // implementation adapted from
    // https://github.com/transmissions11/solmate/blob/e8f96f25d48fe702117ce76c79228ca4f20206cb/src/utils/SafeTransferLib.sol

    /**
     * @notice Transfer token amount.  Amount is sent from caller address to `to` address.
     */
    function transfer(IERC20 token, address to, uint256 amount) internal {
        bool success;
        assembly ("memory-safe") {
            // We'll write our calldata to this slot below, but restore it later.
            let memPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(memPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            // Append arguments. Addresses are assumed clean. Transfer will fail otherwise.
            mstore(add(memPointer, 0x4), to)
            mstore(add(memPointer, 0x24), amount) // Append the "amount" argument.
            // 68 bytes total

            // fail if reverted; only allocate 32 bytes for return to ensure we
            // only use mem slot 0 which is scatch space and memory safe to use.
            success := call(gas(), token, 0, memPointer, 68, 0, 32)
            // handle transfers that return 1/true and ensure the value is from
            // the return and not dirty bits left in the scratch space.
            let returnedOne := and(eq(mload(0), 1), gt(returndatasize(), 31))
            // handle transfers that return nothing
            let noReturn := iszero(returndatasize())
            // good if didn't revert and the return is either empty or true
            success := and(success, or(returnedOne, noReturn))
        }

        if (!success) revert TransferFailed(token, to, amount);
    }

    /**
     * @notice Transfer token amount.  Amount is sent from `from` address to `to` address.
     */
    function transferFrom(IERC20 token, address from, address to, uint256 amount) internal {
        bool success;

        assembly ("memory-safe") {
            // We'll write our calldata to this slot below, but restore it later.
            let memPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(memPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            // Append arguments. Addresses are assumed clean. Transfer will fail otherwise.
            mstore(add(memPointer, 0x4), from) // Append the "from" argument.
            mstore(add(memPointer, 0x24), to) // Append the "to" argument.
            mstore(add(memPointer, 0x44), amount) // Append the "amount" argument.
            // 100 bytes total

            // fail if reverted; only allocate 32 bytes for return to ensure we
            // only use mem slot 0 which is scatch space and memory safe to use.
            success := call(gas(), token, 0, memPointer, 100, 0, 32)
            // handle transfers that return 1/true and ensure the value is from
            // the return and not dirty bits left in the scratch space.
            let returnedOne := and(eq(mload(0), 1), gt(returndatasize(), 31))
            // handle transfers that return nothing
            let noReturn := iszero(returndatasize())
            // good if didn't revert and the return is either empty or true
            success := and(success, or(returnedOne, noReturn))
        }

        if (!success) revert TransferFromFailed(token, from, to, amount);
    }
}

File 11 of 34 : Checks.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IMaverickV2Pool} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Pool.sol";
import {IChecks} from "./IChecks.sol";
import {PoolInspection} from "../libraries/PoolInspection.sol";

abstract contract Checks is IChecks {
    /// @inheritdoc IChecks
    function checkSqrtPrice(IMaverickV2Pool pool, uint256 minSqrtPrice, uint256 maxSqrtPrice) public payable {
        uint256 sqrtPrice = PoolInspection.poolSqrtPrice(pool);
        if (sqrtPrice < minSqrtPrice || sqrtPrice > maxSqrtPrice)
            revert PositionExceededPriceBounds(sqrtPrice, minSqrtPrice, maxSqrtPrice);
    }

    /// @inheritdoc IChecks
    function checkDeadline(uint256 deadline) public payable {
        if (block.timestamp > deadline) revert PositionDeadlinePassed(deadline, block.timestamp);
    }
}

File 12 of 34 : IChecks.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IMaverickV2Pool} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Pool.sol";

interface IChecks {
    error PositionExceededPriceBounds(uint256 sqrtPrice, uint256 minSqrtPrice, uint256 maxSqrtPrice);
    error PositionDeadlinePassed(uint256 deadline, uint256 blockTimestamp);

    /**
     * @notice Function to check if the price of a pool is within specified bounds.
     * @param pool The MaverickV2Pool contract to check.
     * @param minSqrtPrice The minimum acceptable square root price.
     * @param maxSqrtPrice The maximum acceptable square root price.
     */
    function checkSqrtPrice(IMaverickV2Pool pool, uint256 minSqrtPrice, uint256 maxSqrtPrice) external payable;

    /**
     * @notice Function to check if a given deadline has passed.
     * @param deadline The timestamp representing the deadline.
     */
    function checkDeadline(uint256 deadline) external payable;
}

File 13 of 34 : IMaverickV2Router.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {ICallbackOperations} from "../routerbase/ICallbackOperations.sol";
import {IPushOperations} from "../routerbase/IPushOperations.sol";
import {IPayment} from "../paymentbase/IPayment.sol";
import {IChecks} from "../base/IChecks.sol";

/* solhint-disable no-empty-blocks */
interface IMaverickV2Router is IPayment, IChecks, ICallbackOperations, IPushOperations {}

File 14 of 34 : BytesLib.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.25;

// Adapted from https://github.com/GNSPS/solidity-bytes-utils/blob/1dff13ef21304eb3634cb9e7f86c119cf280bd35/contracts/BytesLib.sol
library BytesLib {
    error BytesLibToBoolOutOfBounds();
    error BytesLibToAddressOutOfBounds();
    error BytesLibSliceOverflow();
    error BytesLibSliceOutOfBounds();
    error BytesLibInvalidLength(uint256 inputLength, uint256 expectedLength);

    function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {
        // 31 is added to _length in assembly; need to check here that that
        // operation will not overflow
        if (_length > type(uint256).max - 31) revert BytesLibSliceOverflow();
        if (_bytes.length < _start + _length) revert BytesLibSliceOutOfBounds();

        bytes memory tempBytes;

        assembly ("memory-safe") {
            switch iszero(_length)
            case 0 {
                // Get a location of some free memory and store it in tempBytes as
                // Solidity does for memory variables.
                tempBytes := mload(0x40)

                // The first word of the slice result is potentially a partial
                // word read from the original array. To read it, we calculate
                // the length of that partial word and start copying that many
                // bytes into the array. The first word we copy will start with
                // data we don't care about, but the last `lengthmod` bytes will
                // land at the beginning of the contents of the new array. When
                // we're done copying, we overwrite the full first word with
                // the actual length of the slice.
                let lengthmod := and(_length, 31)

                // The multiplication in the next line is necessary
                // because when slicing multiples of 32 bytes (lengthmod == 0)
                // the following copy loop was copying the origin's length
                // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    // The multiplication in the next line has the same exact purpose
                    // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    mstore(mc, mload(cc))
                }

                mstore(tempBytes, _length)

                //update free-memory pointer
                //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)
                //zero out the 32 bytes slice we are about to return
                //we need to do it because Solidity does not garbage collect
                mstore(tempBytes, 0)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address addr) {
        unchecked {
            if (_bytes.length < _start + 20) revert BytesLibToAddressOutOfBounds();

            assembly ("memory-safe") {
                addr := and(0xffffffffffffffffffffffffffffffffffffffff, mload(add(add(_bytes, 20), _start)))
            }
        }
    }

    function toBool(bytes memory _bytes, uint256 _start) internal pure returns (bool) {
        unchecked {
            if (_bytes.length < _start + 1) revert BytesLibToBoolOutOfBounds();
            uint8 tempUint;

            assembly ("memory-safe") {
                tempUint := mload(add(add(_bytes, 1), _start))
            }

            return tempUint == 1;
        }
    }

    function toAddressAddressBoolUint128Uint128(
        bytes memory _bytes
    ) internal pure returns (address addr1, address addr2, bool bool_, uint128 amount1, uint128 amount2) {
        if (_bytes.length != 73) revert BytesLibInvalidLength(_bytes.length, 73);
        uint8 temp;
        assembly ("memory-safe") {
            addr1 := and(0xffffffffffffffffffffffffffffffffffffffff, mload(add(_bytes, 20)))
            addr2 := and(0xffffffffffffffffffffffffffffffffffffffff, mload(add(_bytes, 40)))
            temp := mload(add(_bytes, 41))
            amount1 := and(0xffffffffffffffffffffffffffffffff, mload(add(_bytes, 57)))
            amount2 := and(0xffffffffffffffffffffffffffffffff, mload(add(_bytes, 73)))
        }
        bool_ = temp == 1;
    }
}

File 15 of 34 : PackLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

// adapted from https://github.com/latticexyz/mud/blob/main/packages/store/src/Slice.sol
import {IMaverickV2Pool} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Pool.sol";
import {SafeCast as Cast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";

import {BytesLib} from "./BytesLib.sol";

library PackLib {
    using Cast for uint256;
    using BytesLib for bytes;

    function unpackExactInputSingleArgsAmounts(
        bytes memory argsPacked
    )
        internal
        pure
        returns (address recipient, IMaverickV2Pool pool, bool tokenAIn, uint256 amountIn, uint256 amountOutMinimum)
    {
        address pool_;
        (recipient, pool_, tokenAIn, amountIn, amountOutMinimum) = argsPacked.toAddressAddressBoolUint128Uint128();
        pool = IMaverickV2Pool(pool_);
    }

    function unpackAddLiquidityArgs(
        bytes memory argsPacked
    ) internal pure returns (IMaverickV2Pool.AddLiquidityParams memory args) {
        args.kind = uint8(argsPacked[0]);
        args.ticks = unpackInt32Array(argsPacked.slice(1, argsPacked.length - 1));
        uint256 startByte = args.ticks.length * 4 + 2;
        args.amounts = unpackUint128Array(argsPacked.slice(startByte, argsPacked.length - startByte));
    }

    function packAddLiquidityArgs(
        IMaverickV2Pool.AddLiquidityParams memory args
    ) internal pure returns (bytes memory argsPacked) {
        argsPacked = abi.encodePacked(args.kind);
        argsPacked = bytes.concat(argsPacked, packArray(args.ticks));
        argsPacked = bytes.concat(argsPacked, packArray(args.amounts));
    }

    function packAddLiquidityArgsToArray(
        IMaverickV2Pool.AddLiquidityParams memory args
    ) internal pure returns (bytes[] memory argsPacked) {
        argsPacked = new bytes[](1);
        argsPacked[0] = packAddLiquidityArgs(args);
    }

    function packAddLiquidityArgsArray(
        IMaverickV2Pool.AddLiquidityParams[] memory args
    ) internal pure returns (bytes[] memory argsPacked) {
        argsPacked = new bytes[](args.length);
        for (uint256 k; k < args.length; k++) {
            argsPacked[k] = packAddLiquidityArgs(args[k]);
        }
    }

    function unpackInt32Array(bytes memory input) internal pure returns (int32[] memory array) {
        uint256[] memory output = _unpackArray(input, 4);
        assembly ("memory-safe") {
            array := output
        }
    }

    function unpackUint128Array(bytes memory input) internal pure returns (uint128[] memory array) {
        uint256[] memory output = _unpackArray(input, 16);
        assembly ("memory-safe") {
            array := output
        }
    }

    function unpackUint88Array(bytes memory input) internal pure returns (uint88[] memory array) {
        uint256[] memory output = _unpackArray(input, 11);
        assembly ("memory-safe") {
            array := output
        }
    }

    function packArray(int32[] memory array) internal pure returns (bytes memory output) {
        uint256[] memory input;
        assembly ("memory-safe") {
            input := array
        }
        output = _packArray(input, 4);
    }

    function packArray(uint128[] memory array) internal pure returns (bytes memory output) {
        uint256[] memory input;
        assembly ("memory-safe") {
            input := array
        }
        output = _packArray(input, 16);
    }

    function packArray(uint88[] memory array) internal pure returns (bytes memory output) {
        uint256[] memory input;
        assembly ("memory-safe") {
            input := array
        }
        output = _packArray(input, 11);
    }

    /*
     * @notice [length, array[0], array[1],..., array[length-1]]. length is 1 bytes.
     * @dev Unpacked signed array elements will contain "dirty bits".  That is,
     * this function does not 0xf pad signed return elements.
     */
    function _unpackArray(bytes memory input, uint256 elementBytes) internal pure returns (uint256[] memory array) {
        uint256 packedPointer;
        uint256 arrayLength;
        assembly ("memory-safe") {
            // read from input pointer + 32 bytes
            // pad 1-byte length value to fill 32 bytes (248 pad bits)
            arrayLength := shr(248, mload(add(input, 0x20)))
            packedPointer := add(input, 0x21)
        }

        uint256 padRight = 256 - 8 * elementBytes;
        assembly ("memory-safe") {
            // Allocate a word for each element, and a word for the array's length
            let allocateBytes := add(mul(arrayLength, 32), 0x20)
            // Allocate memory and update the free memory pointer
            array := mload(0x40)
            mstore(0x40, add(array, allocateBytes))

            // Store array length
            mstore(array, arrayLength)

            for {
                let i := 0
                let arrayCursor := add(array, 0x20) // skip array length
                let packedCursor := packedPointer
            } lt(i, arrayLength) {
                // Loop until we reach the end of the array
                i := add(i, 1)
                arrayCursor := add(arrayCursor, 0x20) // increment array pointer by one word
                packedCursor := add(packedCursor, elementBytes) // increment packed pointer by one element size
            } {
                mstore(arrayCursor, shr(padRight, mload(packedCursor))) // unpack one array element
            }
        }
    }

    /*
     * @dev [length, array[0], array[1],..., array[length-1]]. length is 1 bytes.
     */
    function _packArray(uint256[] memory array, uint256 elementBytes) internal pure returns (bytes memory output) {
        // cast to check size fits in 8 bits
        uint8 arrayLength = array.length.toUint8();
        uint256 packedLength = arrayLength * elementBytes + 1;

        output = new bytes(packedLength);

        uint256 padLeft = 256 - 8 * elementBytes;
        assembly ("memory-safe") {
            // Store array length
            mstore(add(output, 0x20), shl(248, arrayLength))

            for {
                let i := 0
                let arrayCursor := add(array, 0x20) // skip array length
                let packedCursor := add(output, 0x21) // skip length
            } lt(i, arrayLength) {
                // Loop until we reach the end of the array
                i := add(i, 1)
                arrayCursor := add(arrayCursor, 0x20) // increment array pointer by one word
                packedCursor := add(packedCursor, elementBytes) // increment packed pointer by one element size
            } {
                mstore(packedCursor, shl(padLeft, mload(arrayCursor))) // pack one array element
            }
        }
    }
}

File 16 of 34 : Path.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {IMaverickV2Pool} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Pool.sol";
import {BytesLib} from "./BytesLib.sol";

/**
 * @notice Path is [pool_addr, tokenAIn, pool_addr, tokenAIn ...], alternating 20
 * bytes and then one byte for the tokenAIn bool.
 */
library Path {
    using BytesLib for bytes;

    /**
     * @notice The length of the bytes encoded address.
     */
    uint256 private constant ADDR_SIZE = 20;

    /**
     * @notice The length of the bytes encoded bool.
     */
    uint256 private constant BOOL_SIZE = 1;

    /**
     * @notice The offset of a single token address and pool address.
     */
    uint256 private constant NEXT_OFFSET = ADDR_SIZE + BOOL_SIZE;

    /**
     * @notice Returns true iff the path contains two or more pools.
     * @param path The encoded swap path.
     * @return True if path contains two or more pools, otherwise false.
     */
    function hasMultiplePools(bytes memory path) internal pure returns (bool) {
        return path.length > NEXT_OFFSET;
    }

    /**
     * @notice Decodes the first pool in path.
     * @param path The bytes encoded swap path.
     */
    function decodeFirstPool(bytes memory path) internal pure returns (IMaverickV2Pool pool, bool tokenAIn) {
        pool = IMaverickV2Pool(path.toAddress(0));
        tokenAIn = path.toBool(ADDR_SIZE);
    }

    function decodeNextPoolAddress(bytes memory path) internal pure returns (address pool) {
        pool = path.toAddress(NEXT_OFFSET);
    }

    /**
     * @notice Skips a token + pool element from the buffer and returns the
     * remainder.
     * @param path The swap path.
     * @return The remaining token + pool elements in the path.
     */
    function skipToken(bytes memory path) internal pure returns (bytes memory) {
        return path.slice(NEXT_OFFSET, path.length - NEXT_OFFSET);
    }
}

File 17 of 34 : PoolInspection.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {SafeCast as Cast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";

import {IMaverickV2Pool} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Pool.sol";
import {Math} from "@maverick/v2-common/contracts/libraries/Math.sol";
import {PoolLib} from "@maverick/v2-common/contracts/libraries/PoolLib.sol";
import {TickMath} from "@maverick/v2-common/contracts/libraries/TickMath.sol";

library PoolInspection {
    using Cast for uint256;

    /**
     * @dev Calculates the square root price of a given Maverick V2 pool.
     * @param pool The Maverick V2 pool to inspect.
     * @return sqrtPrice The square root price of the pool.
     */
    function poolSqrtPrice(IMaverickV2Pool pool) internal view returns (uint256 sqrtPrice) {
        int32 activeTick = pool.getState().activeTick;
        IMaverickV2Pool.TickState memory tickState = pool.getTick(activeTick);

        (uint256 sqrtLowerTickPrice, uint256 sqrtUpperTickPrice) = TickMath.tickSqrtPrices(
            pool.tickSpacing(),
            activeTick
        );

        (sqrtPrice, ) = TickMath.getTickSqrtPriceAndL(
            tickState.reserveA,
            tickState.reserveB,
            sqrtLowerTickPrice,
            sqrtUpperTickPrice
        );
    }

    /**
     * @dev Retrieves the reserves of a user's subaccount for a specific bin.
     */
    function userSubaccountBinReserves(
        IMaverickV2Pool pool,
        address user,
        uint256 subaccount,
        uint32 binId
    ) internal view returns (uint256 amountA, uint256 amountB, int32 tick, uint256 liquidity) {
        IMaverickV2Pool.BinState memory bin = pool.getBin(binId);

        uint256 userBinLpBalance = pool.balanceOf(user, subaccount, binId);
        while (bin.mergeId != 0) {
            userBinLpBalance = bin.totalSupply == 0
                ? 0
                : Math.mulDivFloor(userBinLpBalance, bin.mergeBinBalance, bin.totalSupply);
            bin = pool.getBin(bin.mergeId);
        }
        tick = bin.tick;

        IMaverickV2Pool.TickState memory tickState = pool.getTick(tick);

        uint256 activeBinDeltaLpBalance = Math.min(userBinLpBalance, bin.totalSupply);

        uint128 deltaTickBalance = Math
            .mulDivDown(activeBinDeltaLpBalance, bin.tickBalance, bin.totalSupply)
            .toUint128();

        deltaTickBalance = Math.min128(deltaTickBalance, tickState.totalSupply);

        (amountA, amountB) = PoolLib.binReserves(
            deltaTickBalance,
            tickState.reserveA,
            tickState.reserveB,
            tickState.totalSupply
        );

        {
            (uint256 sqrtLowerTickPrice, uint256 sqrtUpperTickPrice) = TickMath.tickSqrtPrices(
                pool.tickSpacing(),
                tick
            );
            liquidity = TickMath.getTickL(amountA, amountB, sqrtLowerTickPrice, sqrtUpperTickPrice);
        }
    }

    /**
     * @dev Retrieves the reserves of a token for all bins associated with it.
     * Bin reserve amounts are in pool D18 scale units.
     */
    function subaccountPositionInformation(
        IMaverickV2Pool pool,
        address user,
        uint256 subaccount,
        uint32[] memory binIds
    )
        internal
        view
        returns (
            uint256 amountA,
            uint256 amountB,
            uint256[] memory binAAmounts,
            uint256[] memory binBAmounts,
            int32[] memory ticks,
            uint256[] memory liquidities
        )
    {
        binAAmounts = new uint256[](binIds.length);
        binBAmounts = new uint256[](binIds.length);
        ticks = new int32[](binIds.length);
        liquidities = new uint256[](binIds.length);

        for (uint256 i; i < binIds.length; i++) {
            (binAAmounts[i], binBAmounts[i], ticks[i], liquidities[i]) = userSubaccountBinReserves(
                pool,
                user,
                subaccount,
                binIds[i]
            );
            amountA += binAAmounts[i];
            amountB += binBAmounts[i];
        }
        {
            uint256 tokenAScale = pool.tokenAScale();
            uint256 tokenBScale = pool.tokenBScale();
            amountA = Math.ammScaleToTokenScale(amountA, tokenAScale, false);
            amountB = Math.ammScaleToTokenScale(amountB, tokenBScale, false);
        }
    }

    function binLpBalances(
        IMaverickV2Pool pool,
        uint32[] memory binIds,
        uint256 subaccount
    ) internal view returns (uint128[] memory amounts) {
        amounts = new uint128[](binIds.length);
        for (uint256 i = 0; i < binIds.length; i++) {
            amounts[i] = pool.balanceOf(address(this), subaccount, binIds[i]);
        }
    }

    function lpBalanceForTargetReserveAmounts(
        IMaverickV2Pool pool,
        uint32 binId,
        uint256 amountA,
        uint256 amountB,
        uint256 scaleA,
        uint256 scaleB
    ) internal view returns (IMaverickV2Pool.AddLiquidityParams memory addParams) {
        amountA = Math.tokenScaleToAmmScale(amountA, scaleA);
        amountB = Math.tokenScaleToAmmScale(amountB, scaleB);

        IMaverickV2Pool.BinState memory bin = pool.getBin(binId);
        uint128[] memory amounts = new uint128[](1);

        IMaverickV2Pool.TickState memory tickState = pool.getTick(bin.tick);
        uint256 numerator = Math.max(1, uint256(tickState.totalSupply)) * Math.max(1, uint256(bin.totalSupply));

        if (amountA != 0) {
            uint256 denominator = Math.max(1, uint256(bin.tickBalance)) * uint256(tickState.reserveA);
            amounts[0] = Math.mulDivFloor(amountA, numerator, denominator).toUint128();
        }
        if (amountB != 0) {
            uint256 denominator = Math.max(1, uint256(bin.tickBalance)) * uint256(tickState.reserveB);

            if (amountA != 0) {
                amounts[0] = Math.min128(amounts[0], Math.mulDivFloor(amountB, numerator, denominator).toUint128());
            } else {
                amounts[0] = Math.mulDivFloor(amountB, numerator, denominator).toUint128();
            }
        }
        {
            int32[] memory ticks = new int32[](1);
            ticks[0] = bin.tick;
            addParams = IMaverickV2Pool.AddLiquidityParams({kind: bin.kind, ticks: ticks, amounts: amounts});
        }
    }

    function maxRemoveParams(
        IMaverickV2Pool pool,
        uint32 binId,
        address user,
        uint256 subaccount
    ) internal view returns (IMaverickV2Pool.RemoveLiquidityParams memory params) {
        uint32[] memory binIds = new uint32[](1);
        uint128[] memory amounts = new uint128[](1);
        binIds[0] = binId;
        amounts[0] = pool.balanceOf(user, subaccount, binId);
        params = IMaverickV2Pool.RemoveLiquidityParams({binIds: binIds, amounts: amounts});
    }
}

File 18 of 34 : IPayment.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import {IPayableMulticall} from "@maverick/v2-common/contracts/base/IPayableMulticall.sol";

import {IState} from "./IState.sol";

interface IPayment is IPayableMulticall, IState {
    error PaymentSenderNotWETH9();
    error PaymentInsufficientBalance(address token, uint256 amountMinimum, uint256 contractBalance);

    receive() external payable;

    /**
     * @notice Unwrap WETH9 tokens into ETH and send that balance to recipient.
     * If less than amountMinimum WETH is avialble, then revert.
     */
    function unwrapWETH9(uint256 amountMinimum, address recipient) external payable;

    /**
     * @notice Transfers specified token amount to recipient
     */
    function sweepTokenAmount(IERC20 token, uint256 amount, address recipient) external payable;

    /**
     * @notice Sweep entire ERC20 token balance on this contract to recipient.
     * If less than amountMinimum balance is avialble, then revert.
     */
    function sweepToken(IERC20 token, uint256 amountMinimum, address recipient) external payable;

    /**
     * @notice Send any ETH on this contract to msg.sender.
     */
    function refundETH() external payable;

    /**
     * @notice For tokenA and tokenB, sweep all of the
     * non-WETH tokens to msg.sender.  Any WETH balance is unwrapped to ETH and
     * then all the ETH on this contract is sent to msg.sender.
     */
    function unwrapAndSweep(
        IERC20 tokenA,
        IERC20 tokenB,
        uint256 tokenAAmountMin,
        uint256 tokenBAmountMin
    ) external payable;
}

File 19 of 34 : IState.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IWETH9} from "./IWETH9.sol";
import {IMaverickV2Factory} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Factory.sol";

interface IState {
    function weth() external view returns (IWETH9 _weth);
    function factory() external view returns (IMaverickV2Factory _factory);
}

File 20 of 34 : IWETH9.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IWETH9 is IERC20 {
    event Deposit(address indexed dst, uint256 wad);
    event Withdrawal(address indexed src, uint256 wad);

    function deposit() external payable;

    function withdraw(uint256) external;
}

File 21 of 34 : Payment.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {TransferLib} from "@maverick/v2-common/contracts/libraries/TransferLib.sol";
import {PayableMulticall} from "@maverick/v2-common/contracts/base/PayableMulticall.sol";

import {IWETH9} from "./IWETH9.sol";
import {State} from "./State.sol";

import {IPayment} from "./IPayment.sol";

/**
 * @notice Payment helper function that lets user sweep ERC20 tokens off the
 * router and liquidity manager.  Also provides mechanism to wrap and unwrap
 * ETH/WETH so that it can be used in the Maverick pools.
 */
abstract contract Payment is State, PayableMulticall, IPayment {
    receive() external payable {
        if (IWETH9(msg.sender) != weth()) revert PaymentSenderNotWETH9();
    }

    /// @inheritdoc IPayment
    function unwrapWETH9(uint256 amountMinimum, address recipient) public payable {
        uint256 balanceWETH9 = weth().balanceOf(address(this));
        if (balanceWETH9 < amountMinimum)
            revert PaymentInsufficientBalance(address(weth()), amountMinimum, balanceWETH9);
        if (balanceWETH9 > 0) {
            weth().withdraw(balanceWETH9);
            Address.sendValue(payable(recipient), balanceWETH9);
        }
    }

    /// @inheritdoc IPayment
    function sweepToken(IERC20 token, uint256 amountMinimum, address recipient) public payable {
        uint256 balanceToken = token.balanceOf(address(this));
        if (balanceToken < amountMinimum)
            revert PaymentInsufficientBalance(address(token), amountMinimum, balanceToken);
        if (balanceToken > 0) {
            TransferLib.transfer(token, recipient, balanceToken);
        }
    }

    /// @inheritdoc IPayment
    function sweepTokenAmount(IERC20 token, uint256 amount, address recipient) public payable {
        TransferLib.transfer(token, recipient, amount);
    }

    /// @inheritdoc IPayment
    function unwrapAndSweep(
        IERC20 tokenA,
        IERC20 tokenB,
        uint256 tokenAAmountMin,
        uint256 tokenBAmountMin
    ) public payable {
        if (address(tokenA) == address(weth())) {
            unwrapWETH9(tokenAAmountMin, msg.sender);
            refundETH();
            sweepToken(tokenB, tokenBAmountMin, msg.sender);
        } else if (address(tokenB) == address(weth())) {
            sweepToken(tokenA, tokenAAmountMin, msg.sender);
            unwrapWETH9(tokenBAmountMin, msg.sender);
            refundETH();
        } else {
            sweepToken(tokenA, tokenAAmountMin, msg.sender);
            sweepToken(tokenB, tokenBAmountMin, msg.sender);
        }
    }

    /// @inheritdoc IPayment
    function refundETH() public payable {
        if (address(this).balance > 0) Address.sendValue(payable(msg.sender), address(this).balance);
    }

    /**
     * @notice Internal function to pay tokens or eth.
     * @param token ERC20 token to pay.
     * @param payer Address of the payer.
     * @param recipient Address of the recipient.
     * @param value Amount of tokens to pay.
     */
    function pay(IERC20 token, address payer, address recipient, uint256 value) internal {
        if (IWETH9(address(token)) == weth() && address(this).balance >= value) {
            weth().deposit{value: value}();
            weth().transfer(recipient, value);
        } else if (payer == address(this)) {
            TransferLib.transfer(token, recipient, value);
        } else {
            TransferLib.transferFrom(token, payer, recipient, value);
        }
    }
}

File 22 of 34 : State.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IMaverickV2Factory} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Factory.sol";
import {IWETH9} from "./IWETH9.sol";
import {IState} from "./IState.sol";

abstract contract State is IState {
    IWETH9 private immutable _weth;
    IMaverickV2Factory private immutable _factory;

    constructor(IMaverickV2Factory __factory, IWETH9 __weth) {
        _factory = __factory;
        _weth = __weth;
    }

    function weth() public view returns (IWETH9 weth_) {
        weth_ = _weth;
    }

    function factory() public view returns (IMaverickV2Factory factory_) {
        factory_ = _factory;
    }
}

File 23 of 34 : CallbackOperations.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IMaverickV2Pool} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Pool.sol";

import {ICallbackOperations} from "./ICallbackOperations.sol";
import {Path} from "../libraries/Path.sol";
import {ExactOutputSlim} from "./ExactOutputSlim.sol";

abstract contract CallbackOperations is ExactOutputSlim, ICallbackOperations {
    using Path for bytes;

    struct CallbackData {
        bytes path;
        address payer;
    }

    uint256 private __amountIn = type(uint256).max;

    /// @inheritdoc ICallbackOperations
    function exactOutputSingle(
        address recipient,
        IMaverickV2Pool pool,
        bool tokenAIn,
        uint256 amountOut,
        uint256 amountInMaximum
    ) public payable returns (uint256 amountIn, uint256 amountOut_) {
        int32 tickLimit = tokenAIn ? type(int32).max : type(int32).min;
        (amountIn, amountOut_) = _exactOutputSingleWithTickCheck(pool, recipient, amountOut, tokenAIn, tickLimit);
        if (amountIn > amountInMaximum) revert RouterTooMuchRequested(amountInMaximum, amountIn);
    }

    /// @inheritdoc ICallbackOperations
    function outputSingleWithTickLimit(
        address recipient,
        IMaverickV2Pool pool,
        bool tokenAIn,
        uint256 amountOut,
        int32 tickLimit,
        uint256 amountInMaximum,
        uint256 amountOutMinimum
    ) public payable returns (uint256 amountIn_, uint256 amountOut_) {
        (amountIn_, amountOut_) = _exactOutputSingleWithTickCheck(pool, recipient, amountOut, tokenAIn, tickLimit);
        if (amountIn_ > amountInMaximum) revert RouterTooMuchRequested(amountInMaximum, amountIn_);
        if (amountOut_ < amountOutMinimum) revert RouterTooLittleReceived(amountOutMinimum, amountOut_);
    }

    /// @inheritdoc ICallbackOperations
    function exactOutputMultiHop(
        address recipient,
        bytes memory path,
        uint256 amountOut,
        uint256 amountInMaximum
    ) public payable returns (uint256 amountIn) {
        // recursively swap through the hops starting with the ouput pool.
        // inside of the swap callback, this contract will call the next pool
        // in the path until it gets to the input pool of the path.
        _exactOutputInternal(amountOut, recipient, CallbackData({path: path, payer: msg.sender}));
        amountIn = __amountIn;
        if (amountIn > amountInMaximum) revert RouterTooMuchRequested(amountInMaximum, amountIn);
        __amountIn = type(uint256).max;
    }

    /// @inheritdoc ICallbackOperations
    function inputSingleWithTickLimit(
        address recipient,
        IMaverickV2Pool pool,
        bool tokenAIn,
        uint256 amountIn,
        int32 tickLimit,
        uint256 amountOutMinimum
    ) public payable returns (uint256 amountIn_, uint256 amountOut) {
        // swap
        IMaverickV2Pool.SwapParams memory swapParams = IMaverickV2Pool.SwapParams({
            amount: amountIn,
            tokenAIn: tokenAIn,
            exactOutput: false,
            tickLimit: tickLimit
        });
        (amountIn_, amountOut) = _swap(pool, recipient, swapParams, abi.encode(msg.sender));
        if (amountOut < amountOutMinimum) revert RouterTooLittleReceived(amountOutMinimum, amountOut);
    }

    function _exactOutputInternal(
        uint256 amountOut,
        address recipient,
        CallbackData memory data
    ) internal returns (uint256 amountIn) {
        if (recipient == address(0)) recipient = address(this);
        (IMaverickV2Pool pool, bool tokenAIn) = data.path.decodeFirstPool();

        int32 tickLimit = tokenAIn ? type(int32).max : type(int32).min;
        IMaverickV2Pool.SwapParams memory swapParams = IMaverickV2Pool.SwapParams({
            amount: amountOut,
            tokenAIn: tokenAIn,
            exactOutput: true,
            tickLimit: tickLimit
        });

        uint256 amountOutReceived;
        (amountIn, amountOutReceived) = _swap(pool, recipient, swapParams, abi.encode(data));
    }

    function maverickV2SwapCallback(
        IERC20 tokenIn,
        uint256 amountToPay,
        uint256,
        bytes calldata _data
    ) external override {
        // only used for either single-hop exactinput calls with a tick limit,
        // or exactouput calls.  if the path has more than one pool, then this
        // is an exactouput multihop swap.
        if (amountToPay == 0) revert RouterZeroSwap();
        if (!factory().isFactoryPool(IMaverickV2Pool(msg.sender))) revert RouterNotFactoryPool();

        if (_data.length == 32) {
            // exact in
            address payer = abi.decode(_data, (address));
            pay(tokenIn, payer, msg.sender, amountToPay);
        } else {
            // exact out
            CallbackData memory data = abi.decode(_data, (CallbackData));

            if (data.path.hasMultiplePools()) {
                data.path = data.path.skipToken();
                _exactOutputInternal(amountToPay, msg.sender, data);
            } else {
                // must be at first/input pool
                __amountIn = amountToPay;
                pay(tokenIn, data.payer, msg.sender, amountToPay);
            }
        }
    }
}

File 24 of 34 : ExactOutputSlim.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IMaverickV2Pool} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Pool.sol";

import {Payment} from "../paymentbase/Payment.sol";
import {IExactOutputSlim} from "./IExactOutputSlim.sol";
import {Swap} from "./Swap.sol";

abstract contract ExactOutputSlim is Payment, Swap, IExactOutputSlim {
    /**
     * @dev Callback function called by Maverick V2 pools when swapping tokens.
     * @param tokenIn The input token.
     * @param amountToPay The amount to pay.
     * @param data Additional data.
     */
    function maverickV2SwapCallback(
        IERC20 tokenIn,
        uint256 amountToPay,
        uint256,
        bytes calldata data
    ) external virtual {
        if (!factory().isFactoryPool(IMaverickV2Pool(msg.sender))) revert RouterNotFactoryPool();
        address payer = abi.decode(data, (address));
        if (amountToPay != 0) pay(tokenIn, payer, msg.sender, amountToPay);
    }

    /**
     * @dev Perform a swap with an exact output amount.
     * @param recipient The recipient of the swapped tokens.
     * @param pool The MaverickV2 pool to use for the swap.
     * @param tokenAIn Whether token A is the input token.
     * @param amountOut The exact output amount.
     * @param tickLimit The tick limit for the swap.
     * @return amountIn The input amount required to achieve the exact output.
     * @return amountOut_ The actual output amount received from the swap.
     */
    function exactOutputSingleMinimal(
        address recipient,
        IMaverickV2Pool pool,
        bool tokenAIn,
        uint256 amountOut,
        int32 tickLimit
    ) public payable returns (uint256 amountIn, uint256 amountOut_) {
        (amountIn, amountOut_) = _exactOutputSingleWithTickCheck(pool, recipient, amountOut, tokenAIn, tickLimit);
    }

    /**
     * @dev Perform an exact output single swap with tick limit validation.
     * @param pool The MaverickV2 pool to use for the swap.
     * @param recipient The recipient of the swapped tokens.
     * @param amountOut The exact output amount.
     * @param tokenAIn Whether token A is the input token.
     * @param tickLimit The tick limit for the swap.
     * @return amountIn The input amount required to achieve the exact output.
     * @return _amountOut The actual output amount received from the swap.
     */
    function _exactOutputSingleWithTickCheck(
        IMaverickV2Pool pool,
        address recipient,
        uint256 amountOut,
        bool tokenAIn,
        int32 tickLimit
    ) internal returns (uint256 amountIn, uint256 _amountOut) {
        IMaverickV2Pool.SwapParams memory swapParams = IMaverickV2Pool.SwapParams({
            amount: amountOut,
            tokenAIn: tokenAIn,
            exactOutput: true,
            tickLimit: tickLimit
        });
        (amountIn, _amountOut) = _swap(
            pool,
            (recipient == address(0)) ? address(this) : recipient,
            swapParams,
            abi.encode(msg.sender)
        );
    }
}

File 25 of 34 : ICallbackOperations.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IMaverickV2Pool} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Pool.sol";

import {IExactOutputSlim} from "./IExactOutputSlim.sol";

interface ICallbackOperations is IExactOutputSlim {
    /**
     * @notice Perform an exact output single swap.
     * @param recipient The address of the recipient.
     * @param pool The Maverick V2 pool to swap with.
     * @param tokenAIn A boolean indicating if token A is the input.
     * @param amountOut The amount of output tokens desired.
     * @param amountInMaximum The maximum amount of input tokens allowed.
     * @return amountIn The amount of input tokens used for the swap.
     * @return amountOut_ The actual amount of output tokens received.
     */
    function exactOutputSingle(
        address recipient,
        IMaverickV2Pool pool,
        bool tokenAIn,
        uint256 amountOut,
        uint256 amountInMaximum
    ) external payable returns (uint256 amountIn, uint256 amountOut_);

    /**
     * @notice Perform an output-specified single swap with tick limit check.
     * @param recipient The address of the recipient.
     * @param pool The Maverick V2 pool to swap with.
     * @param tokenAIn A boolean indicating if token A is the input.
     * @param amountOut The amount of output tokens desired.
     * @param tickLimit The tick limit for the swap.
     * @param amountInMaximum The maximum amount of input tokens allowed.
     * @param amountOutMinimum The minimum amount of output tokens expected.
     * @return amountIn_ The actual amount of input tokens used for the swap.
     * @return amountOut_ The actual amount of output tokens received.  This
     * amount can vary from the requested amountOut due to the tick limit.  If
     * the pool swaps to the tick limit, it will stop filling the order and
     * return the amount out swapped up to the ticklimit to the user.
     */
    function outputSingleWithTickLimit(
        address recipient,
        IMaverickV2Pool pool,
        bool tokenAIn,
        uint256 amountOut,
        int32 tickLimit,
        uint256 amountInMaximum,
        uint256 amountOutMinimum
    ) external payable returns (uint256 amountIn_, uint256 amountOut_);

    /**
     * @notice Perform an exact output multihop swap.
     * @param recipient The recipient address.
     * @param path The swap path as encoded bytes.
     * @param amountOut The exact output amount.
     * @param amountInMaximum The maximum input amount allowed.
     * @return amountIn The input amount for the swap.
     */
    function exactOutputMultiHop(
        address recipient,
        bytes memory path,
        uint256 amountOut,
        uint256 amountInMaximum
    ) external payable returns (uint256 amountIn);

    /**
     * @notice Perform an input-specified single swap with tick limit check.
     * @param recipient The address of the recipient.
     * @param pool The Maverick V2 pool to swap with.
     * @param tokenAIn A boolean indicating if token A is the input.
     * @param amountIn The amount of input tokens.
     * @param tickLimit The tick limit for the swap.
     * @param amountOutMinimum The minimum amount of output tokens expected.
     * @return amountIn_ The actual input amount used for the swap. This may
     * differ from the amount the caller specified if the pool reaches the tick
     * limit.  In that case, the pool will consume the input swap amount up to
     * the tick limit and return the resulting output amount to the user.
     * @return amountOut The amount of output tokens received.
     */
    function inputSingleWithTickLimit(
        address recipient,
        IMaverickV2Pool pool,
        bool tokenAIn,
        uint256 amountIn,
        int32 tickLimit,
        uint256 amountOutMinimum
    ) external payable returns (uint256 amountIn_, uint256 amountOut);
}

File 26 of 34 : IExactOutputSlim.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IMaverickV2Pool} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Pool.sol";

import {IRouterErrors} from "./IRouterErrors.sol";

interface IExactOutputSlim is IRouterErrors {
    function exactOutputSingleMinimal(
        address recipient,
        IMaverickV2Pool pool,
        bool tokenAIn,
        uint256 amountOut,
        int32 tickLimit
    ) external payable returns (uint256 amountIn, uint256 amountOut_);
}

File 27 of 34 : IPushOperations.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IMaverickV2Pool} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Pool.sol";

import {IRouterErrors} from "./IRouterErrors.sol";

interface IPushOperations is IRouterErrors {
    /**
     * @notice Perform an exact input single swap with compressed input values.
     */
    function exactInputSinglePackedArgs(bytes memory argsPacked) external payable returns (uint256 amountOut);

    /**
     * @notice Perform an exact input single swap without tick limit check.
     * @param recipient The address of the recipient.
     * @param pool The Maverick V2 pool to swap with.
     * @param tokenAIn True is tokenA is the input token.  False is tokenB is
     * the input token.
     * @param amountIn The amount of input tokens.
     * @param amountOutMinimum The minimum amount of output tokens expected.
     */
    function exactInputSingle(
        address recipient,
        IMaverickV2Pool pool,
        bool tokenAIn,
        uint256 amountIn,
        uint256 amountOutMinimum
    ) external payable returns (uint256 amountOut);

    /**
     * @notice Perform an exact input multi-hop swap.
     * @param recipient The address of the recipient.
     * @param path The path of tokens to swap.
     * @param amountIn The amount of input tokens.
     * @param amountOutMinimum The minimum amount of output tokens expected.
     */
    function exactInputMultiHop(
        address recipient,
        bytes memory path,
        uint256 amountIn,
        uint256 amountOutMinimum
    ) external payable returns (uint256 amountOut);
}

File 28 of 34 : IRouterErrors.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

interface IRouterErrors {
    error RouterZeroSwap();
    error RouterNotFactoryPool();
    error RouterTooLittleReceived(uint256 amountOutMinimum, uint256 amountOut);
    error RouterTooMuchRequested(uint256 amountInMaximum, uint256 amountIn);
}

File 29 of 34 : PushOperations.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IMaverickV2Pool} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Pool.sol";

import {PackLib} from "../libraries/PackLib.sol";
import {Payment} from "../paymentbase/Payment.sol";
import {Path} from "../libraries/Path.sol";
import {IPushOperations} from "./IPushOperations.sol";
import {Swap} from "./Swap.sol";

/**
 * @notice Exactinput router operations that can be performed by pushing assets
 * to the pool to swap.
 */
abstract contract PushOperations is Payment, Swap, IPushOperations {
    using Path for bytes;

    /// @inheritdoc IPushOperations
    function exactInputSinglePackedArgs(bytes memory argsPacked) public payable returns (uint256 amountOut) {
        (address recipient, IMaverickV2Pool pool, bool tokenAIn, uint256 amountIn, uint256 amountOutMinimum) = PackLib
            .unpackExactInputSingleArgsAmounts(argsPacked);
        return exactInputSingle(recipient, pool, tokenAIn, amountIn, amountOutMinimum);
    }

    /// @inheritdoc IPushOperations
    function exactInputSingle(
        address recipient,
        IMaverickV2Pool pool,
        bool tokenAIn,
        uint256 amountIn,
        uint256 amountOutMinimum
    ) public payable returns (uint256 amountOut) {
        // pay pool
        pay(tokenAIn ? pool.tokenA() : pool.tokenB(), msg.sender, address(pool), amountIn);

        // swap
        IMaverickV2Pool.SwapParams memory swapParams = IMaverickV2Pool.SwapParams({
            amount: amountIn,
            tokenAIn: tokenAIn,
            exactOutput: false,
            tickLimit: tokenAIn ? type(int32).max : type(int32).min
        });
        (, amountOut) = _swap(pool, recipient, swapParams, bytes(""));

        // check slippage
        if (amountOut < amountOutMinimum) revert RouterTooLittleReceived(amountOutMinimum, amountOut);
    }

    /// @inheritdoc IPushOperations
    function exactInputMultiHop(
        address recipient,
        bytes memory path,
        uint256 amountIn,
        uint256 amountOutMinimum
    ) public payable returns (uint256 amountOut) {
        (IMaverickV2Pool pool, bool tokenAIn) = path.decodeFirstPool();

        // pay first pool
        pay(tokenAIn ? pool.tokenA() : pool.tokenB(), msg.sender, address(pool), amountIn);

        amountOut = amountIn;
        while (true) {
            // if we have more pools, pay next pool, if not, pay recipient
            bool stillMultiPoolSwap = path.hasMultiplePools();
            address nextRecipient = stillMultiPoolSwap ? path.decodeNextPoolAddress() : recipient;

            // do swap and send proceeds to nextRecipient
            IMaverickV2Pool.SwapParams memory swapParams = IMaverickV2Pool.SwapParams({
                amount: amountOut,
                tokenAIn: tokenAIn,
                exactOutput: false,
                tickLimit: tokenAIn ? type(int32).max : type(int32).min
            });
            (, amountOut) = _swap(pool, nextRecipient, swapParams, bytes(""));

            // if there is more path, loop, if not, break
            if (stillMultiPoolSwap) {
                path = path.skipToken();
                (pool, tokenAIn) = path.decodeFirstPool();
            } else {
                break;
            }
        }
        if (amountOut < amountOutMinimum) revert RouterTooLittleReceived(amountOutMinimum, amountOut);
    }
}

File 30 of 34 : Swap.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IMaverickV2Pool} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Pool.sol";

/**
 * @notice Base contract support for swaps
 */
abstract contract Swap {
    /**
     * @notice Internal swap function.  Override this function to add logic
     * before or after a swap.
     */
    function _swap(
        IMaverickV2Pool pool,
        address recipient,
        IMaverickV2Pool.SwapParams memory params,
        bytes memory data
    ) internal virtual returns (uint256 amountIn, uint256 amountOut) {
        (amountIn, amountOut) = pool.swap(recipient, params, data);
    }
}

File 31 of 34 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

File 32 of 34 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}

File 33 of 34 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

File 34 of 34 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev An uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, value);
        }
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, value);
        }
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, value);
        }
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, value);
        }
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, value);
        }
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, value);
        }
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 5500
  },
  "viaIR": true,
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IMaverickV2Factory","name":"_factory","type":"address"},{"internalType":"contract IWETH9","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"inputLength","type":"uint256"},{"internalType":"uint256","name":"expectedLength","type":"uint256"}],"name":"BytesLibInvalidLength","type":"error"},{"inputs":[],"name":"BytesLibSliceOutOfBounds","type":"error"},{"inputs":[],"name":"BytesLibSliceOverflow","type":"error"},{"inputs":[],"name":"BytesLibToAddressOutOfBounds","type":"error"},{"inputs":[],"name":"BytesLibToBoolOutOfBounds","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"uint256","name":"contractBalance","type":"uint256"}],"name":"PaymentInsufficientBalance","type":"error"},{"inputs":[],"name":"PaymentSenderNotWETH9","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"blockTimestamp","type":"uint256"}],"name":"PositionDeadlinePassed","type":"error"},{"inputs":[{"internalType":"uint256","name":"sqrtPrice","type":"uint256"},{"internalType":"uint256","name":"minSqrtPrice","type":"uint256"},{"internalType":"uint256","name":"maxSqrtPrice","type":"uint256"}],"name":"PositionExceededPriceBounds","type":"error"},{"inputs":[],"name":"RouterNotFactoryPool","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"RouterTooLittleReceived","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountInMaximum","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"RouterTooMuchRequested","type":"error"},{"inputs":[],"name":"RouterZeroSwap","type":"error"},{"inputs":[{"internalType":"int256","name":"tick","type":"int256"}],"name":"TickMaxExceeded","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferFailed","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferFromFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"checkDeadline","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"uint256","name":"minSqrtPrice","type":"uint256"},{"internalType":"uint256","name":"maxSqrtPrice","type":"uint256"}],"name":"checkSqrtPrice","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"name":"exactInputMultiHop","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"bool","name":"tokenAIn","type":"bool"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"name":"exactInputSingle","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"argsPacked","type":"bytes"}],"name":"exactInputSinglePackedArgs","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"name":"exactOutputMultiHop","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"bool","name":"tokenAIn","type":"bool"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"name":"exactOutputSingle","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut_","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"bool","name":"tokenAIn","type":"bool"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"int32","name":"tickLimit","type":"int32"}],"name":"exactOutputSingleMinimal","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut_","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract IMaverickV2Factory","name":"factory_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"bool","name":"tokenAIn","type":"bool"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"int32","name":"tickLimit","type":"int32"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"name":"inputSingleWithTickLimit","outputs":[{"internalType":"uint256","name":"amountIn_","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountToPay","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"maverickV2SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"bool","name":"tokenAIn","type":"bool"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"int32","name":"tickLimit","type":"int32"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"name":"outputSingleWithTickLimit","outputs":[{"internalType":"uint256","name":"amountIn_","type":"uint256"},{"internalType":"uint256","name":"amountOut_","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"refundETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepTokenAmount","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"tokenA","type":"address"},{"internalType":"contract IERC20","name":"tokenB","type":"address"},{"internalType":"uint256","name":"tokenAAmountMin","type":"uint256"},{"internalType":"uint256","name":"tokenBAmountMin","type":"uint256"}],"name":"unwrapAndSweep","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH9","name":"weth_","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c03460a857601f6127c538819003918201601f19168301916001600160401b0383118484101760ad57808492604094855283398101031260a85780516001600160a01b0391828216820360a85760200151918216820360a85760a05260805260001960005560405161270190816100c48239608051818181602601528181610baf01528181610ec30152818161136e0152611998015260a05181818161019d01526109fb0152f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe60406080815260049081361015610074575b361561001c57600080fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016330361004e57005b517fc0f54629000000000000000000000000000000000000000000000000000000008152fd5b600060e08135811c90816312210e8a146110bc5781631841ad6d1461100157816319b871d314610f8157816328a5b3c914610ee75781633fc8cef314610ea357816349404b7c14610e83578163522ba7eb14610c3a578163670ca18114610b7f57816367ca7c911461095657816369b027ab146108dd578163a3b105ca146108be578163a4af5a7f146107fb578163a6990946146107aa578163ac9650d8146105f2578163b800a206146105a6578163b9e45300146101c557508063c45a01551461017d578063df2ab5bb1461016a5763f16d7904146101545750610011565b6101676101603661131c565b9091611e8d565b80f35b506101676101773661131c565b91611706565b5090346101c157816003193601126101c157602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b5080fd5b8484849260606003193601126105a2576101dd611200565b91602435916001600160a01b03604435941682517f1865c57d00000000000000000000000000000000000000000000000000000000815261012080828981865afa90811561048357899161048d575b5060a09150015160030b908351927f3256cfa900000000000000000000000000000000000000000000000000000000845282888501528084602481855afa938415610483579088949392918a946103a1575b50506020908551948580927fd0c93a7c0000000000000000000000000000000000000000000000000000000082525afa92831561039757889361035d575b506102db8360016102d08461030997611f96565b930160030b90611f96565b906fffffffffffffffffffffffffffffffff602081855116940151166103038383838761234c565b93612426565b908282108015610354575b61031c578580f35b6064955051937ffcb505c700000000000000000000000000000000000000000000000000000000855284015260248301526044820152fd5b50838211610314565b92506020833d60201161038f575b8161037860209383611167565b8101031261038b579151916102db6102bc565b8780fd5b3d915061036b565b84513d8a823e3d90fd5b919450809293503d831161047c575b6103ba8183611167565b8101918082840312610478578551926103d2846110d0565b6103db83611e51565b84526020916103ec60208501611e51565b60208601526103fc888501611e51565b8886015281607f8501121561047457875193610417856110d0565b84918101928311610470579060608c9897969594939201905b828210610449575050505060608201529160208a61027e565b839495969798509281929361045e8293611e7c565b81520191018b97969594939291610430565b8c80fd5b8b80fd5b8980fd5b503d6103b0565b85513d8b823e3d90fd5b80915082813d831161059b575b6104a48183611167565b8101031261059757845190810181811067ffffffffffffffff82111761056b5785526104cf82611e51565b81526104dd60208301611e51565b60208201526104ed858301611e6e565b858201526104fd60608301611e6e565b6060820152608082015164ffffffffff8116810361047857608082015260a08201518060030b81036104785760a082015261053a60c083016114ff565b60c082015261054a848301611e7c565b848201526101008092015160ff811681036104785760a0928201528961022c565b60248a60418b7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b8880fd5b503d61049a565b8380fd5b505060a06003193601126105ef57506105e36105c0611200565b6105c8611216565b6105d061122c565b906105d9611281565b92606435916118a6565b82519182526020820152f35b80fd5b505082602091826003193601126105ef5781359167ffffffffffffffff908184116107a657366023850112156107a657830135908082116107a65760246005923660248260051b880101116107a2579261064b846116ab565b9561065889519788611167565b848752601f19610667866116ab565b0188875b8281106107925750505085917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd82360301925b868110610720578a8a8a8a83519280840190808552835180925280868601968360051b870101940192955b8287106106d65785850386f35b909192938280610710837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08a6001960301865288516112dc565b96019201960195929190926106c9565b8481831b84010135848112156105975783018581013590878211610478576044019080360382136104785789808d610760600196956107769536916111a6565b80519101305af461076f6117f3565b9030611f2d565b610780828c6116c3565b5261078b818b6116c3565b500161069e565b60608a82018301528a910161066b565b8480fd5b8280fd5b82858560206003193601126107a6578135908142116107c7578380f35b6044935051917f3442e977000000000000000000000000000000000000000000000000000000008352820152426024820152fd5b50508260c06003193601126101c157610872610815611200565b61081d611216565b9061082661122c565b9061082f611281565b60a4359688519361083f856110d0565b6064358552151560208501528884015260030b60608301528651923360208501526020845261086d8461111b565b611b8e565b91909280831061088a57505082519182526020820152f35b916044928551927f84ae11480000000000000000000000000000000000000000000000000000000084528301526024820152fd5b6020846108d66108cd3661123b565b9392909261150c565b9051908152f35b8261090885876108ec36611291565b9592908551926108fb8461111b565b8352336020840152611da7565b508354928084116109225750506000196020935551908152f35b604493919251927f4956866a0000000000000000000000000000000000000000000000000000000084528301526024820152fd5b505091346107a65760806003193601126107a657610972611200565b602480359260643567ffffffffffffffff80821161038b573660238301121561038b57818301359681881161059757848301948884019281840192368411610474578915610b57576001600160a01b039a8b978d8351809a7f578eaca40000000000000000000000000000000000000000000000000000000082523384830152818860209d8e937f0000000000000000000000000000000000000000000000000000000000000000165afa918215610b4c5791610b13575b5015610aec57508703610a57575050505003126107a257359283168093036105a257610167923391611985565b91939490929996868287031261047457358381116104745782910180950312610478575197610a858961111b565b8284013591821161047857604492610a9f928501016111e2565b9182885201359283169283810361038b576015928701525111600014610add57505090610ad991610ad08251611c75565b82523390611da7565b5080f35b61016793508285553391611985565b82517f36294ff5000000000000000000000000000000000000000000000000000000008152fd5b90508981813d8311610b45575b610b2a8183611167565b81010312610b4157610b3b906114ff565b38610a2a565b8e80fd5b503d610b20565b8551903d90823e3d90fd5b8690517f63fa284a000000000000000000000000000000000000000000000000000000008152fd5b8260806003193601126105ef57610b94611200565b610b9c611216565b90604435606435916001600160a01b03807f000000000000000000000000000000000000000000000000000000000000000016908181841614600014610bfe5750505090610bef61016793923390611363565b610bf7611350565b3391611706565b8592951614600014610c295750610c2192610c1a913391611706565b3390611363565b610167611350565b919061016793610bf7913391611706565b838584610c4636611291565b9195929390610c5487611902565b909182908215610e105786517f0fc63d100000000000000000000000000000000000000000000000000000000081526020818b816001600160a01b0389165afa908115610e0657610cc19183918891610dd7575b509b94959b5b6001600160a01b03809d16903390611985565b82516015811194908515610dc9576029809110610da15790610d299392918501518c16905b8015610d9557637fffffff905b8a5193610cff856110d0565b845215156020840152878a84015260030b6060830152885192610d218461114b565b878452611b8e565b92159050610d4d57610d3a90611c75565b96610d4488611902565b91989192610cc1565b50935050808310610d62576020838351908152f35b90517f84ae1148000000000000000000000000000000000000000000000000000000008152928301526024820152604490fd5b637fffffff1990610cf3565b8a89517f41a6c181000000000000000000000000000000000000000000000000000000008152fd5b5090610d2992918990610ce6565b610df9915060203d602011610dff575b610df18183611167565b8101906114e0565b8d610ca8565b503d610de7565b88513d88823e3d90fd5b86517f5f64b55b0000000000000000000000000000000000000000000000000000000081526020818b816001600160a01b0389165afa908115610e0657610cc19183918891610e64575b509b94959b610cae565b610e7d915060203d602011610dff57610df18183611167565b8d610e5a565b8285856003193601126101c15761016790610e9c611216565b9035611363565b8284346101c157816003193601126101c157602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b849291506003193601126105ef5750610efe611200565b610f06611216565b91610f2c610f1261122c565b610f1a611281565b9060a4359560c43595606435916118a6565b929093808511610f4c575080831061088a57505082519182526020820152f35b82856044928851927f4956866a0000000000000000000000000000000000000000000000000000000084528301526024820152fd5b505082610fa8610f903661123b565b965091929091908215610ff557637fffffff936118a6565b919092808411610fc057505082519182526020820152f35b90836044928651927f4956866a0000000000000000000000000000000000000000000000000000000084528301526024820152fd5b637fffffff19936118a6565b505060206003193601126105ef5782359067ffffffffffffffff82116105ef575061102f90369084016111e2565b91825160498103611088576020836108d68660148101516001600160a01b0360288301518116602984015192600160ff603987015160496fffffffffffffffffffffffffffffffff98015188169716951614921661150c565b60449251917fd137d34b00000000000000000000000000000000000000000000000000000000835282015260496024820152fd5b82806003193601126105ef57610167611350565b6080810190811067ffffffffffffffff8211176110ec57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040810190811067ffffffffffffffff8211176110ec57604052565b67ffffffffffffffff81116110ec57604052565b6020810190811067ffffffffffffffff8211176110ec57604052565b90601f601f19910116810190811067ffffffffffffffff8211176110ec57604052565b67ffffffffffffffff81116110ec57601f01601f191660200190565b9291926111b28261118a565b916111c06040519384611167565b8294818452818301116111dd578281602093846000960137010152565b600080fd5b9080601f830112156111dd578160206111fd933591016111a6565b90565b600435906001600160a01b03821682036111dd57565b602435906001600160a01b03821682036111dd57565b6044359081151582036111dd57565b60031960a09101126111dd576001600160a01b039060043582811681036111dd579160243590811681036111dd579060443580151581036111dd57906064359060843590565b608435908160030b82036111dd57565b9060806003198301126111dd576004356001600160a01b03811681036111dd57916024359067ffffffffffffffff82116111dd576112d1916004016111e2565b906044359060643590565b919082519283825260005b848110611308575050601f19601f8460006020809697860101520116010190565b6020818301810151848301820152016112e7565b60031960609101126111dd576001600160a01b0360043581811681036111dd57916024359160443590811681036111dd5790565b4761135757565b6113614733611823565b565b6001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001692604051927f70a08231000000000000000000000000000000000000000000000000000000008452306004850152602084602481885afa938415611457576000946114ac575b508084106114635750826113e9575b50505050565b833b156111dd57600080946024604051809781937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528860048401525af19384156114575761143f94611448575b5016611823565b388080806113e3565b61145190611137565b38611438565b6040513d6000823e3d90fd5b6040517fd1cd07af0000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602481019190915260448101849052606490fd5b90936020823d6020116114d8575b816114c760209383611167565b810103126105ef57505192386113d4565b3d91506114ba565b908160209103126111dd57516001600160a01b03811681036111dd5790565b519081151582036111dd57565b93949391929091831561163657604051937f0fc63d100000000000000000000000000000000000000000000000000000000085526020856004816001600160a01b0388165afa8015611457578361157d916115c597600091611617575b505b6001600160a01b038716903390611985565b801561160b57637fffffff905b60405193611597856110d0565b8452151560208401526000604084015260030b6060830152604051926115bc8461114b565b60008452611b8e565b929050828181106115d4575050565b60449250604051917f84ae114800000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b637fffffff199061158a565b611630915060203d602011610dff57610df18183611167565b38611569565b604051937f5f64b55b0000000000000000000000000000000000000000000000000000000085526020856004816001600160a01b0388165afa8015611457578361157d916115c59760009161168c575b5061156b565b6116a5915060203d602011610dff57610df18183611167565b38611686565b67ffffffffffffffff81116110ec5760051b60200190565b80518210156116d75760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b916001600160a01b03831691604051927f70a08231000000000000000000000000000000000000000000000000000000008452306004850152602084602481845afa938415611457576000946117bf575b508184106117745750508161176b57505050565b61136192611e8d565b6040517fd1cd07af0000000000000000000000000000000000000000000000000000000081526001600160a01b03919091166004820152602481019190915260448101839052606490fd5b90936020823d6020116117eb575b816117da60209383611167565b810103126105ef5750519238611757565b3d91506117cd565b3d1561181e573d906118048261118a565b916118126040519384611167565b82523d6000602084013e565b606090565b8147106118765760008080936001600160a01b038294165af16118446117f3565b501561184c57565b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b60246040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152fd5b92936118f994604051936118b9856110d0565b8452151560208401526001604084015260030b60608301526001600160a01b0381166118fd5750305b604051923360208501526020845261086d8461111b565b9091565b6118e2565b90601482511061195b5760148201516001600160a01b0316916015815110611931576015015160ff1660011490565b60046040517f7c1be900000000000000000000000000000000000000000000000000000000008152fd5b60046040517f41a6c181000000000000000000000000000000000000000000000000000000008152fd5b9190916001600160a01b039081811690827f0000000000000000000000000000000000000000000000000000000000000000169485831480611b84575b15611ac357505050823b156111dd57604051917fd0e30db0000000000000000000000000000000000000000000000000000000008352600092838160048189895af18015611ab857611aa1575b50604490836020949560405197889586947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af18015611a9457611a5e575050565b6020823d602011611a8c575b81611a7760209383611167565b810103126105ef5750611a89906114ff565b50565b3d9150611a6a565b50604051903d90823e3d90fd5b90602093611ab0604493611137565b935090611a0f565b6040513d86823e3d90fd5b91959450919081811690308203611ae1575050506113619350611e8d565b606460009182602094959796604051927f23b872dd00000000000000000000000000000000000000000000000000000000845260048401528760248401528960448401525af1601f3d11600160005114163d15171615611b42575050505050565b60849550604051947fa8dced90000000000000000000000000000000000000000000000000000000008652600486015260248501521660448301526064820152fd5b50864710156119c2565b9260609192611c11946001600160a01b03809560409788958651978896879586957f3eece7db000000000000000000000000000000000000000000000000000000008752166004860152805160248601526020810151151560448601528881015115156064860152015160030b608484015260c060a484015260c48301906112dc565b03916000968791165af1918215611c6a5780938193611c32575b5050509091565b919350915082813d8111611c63575b611c4b8183611167565b810103126105ef575060208151910151388080611c2b565b503d611c41565b8351903d90823e3d90fd5b8051907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb91828101818111611d4e57601f1992838211611d7d57805183601511611d4e578311611d245781611cda575050505050604051600081526020810160405290565b9190601560405195601f8316801560051b9182828a01019586010195010101925b808310611d115750601f92508452011660405290565b8351835260209384019390920191611cfb565b60046040517f326b3d3a000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60046040517f648fb3b1000000000000000000000000000000000000000000000000000000008152fd5b611e3992916001600160a01b0380821615611e49575b61086d611dca8551611902565b9092908015611e3d57637fffffff905b60405196611de7886110d0565b8752151560208701526001604087015260030b60608601526040519586916020808401526020611e22835160408087015260808601906112dc565b92015116606083015203601f198101865285611167565b5090565b637fffffff1990611dda565b309150611dbd565b51906fffffffffffffffffffffffffffffffff821682036111dd57565b51908160070b82036111dd57565b519063ffffffff821682036111dd57565b9190916020600060446040517fa9059cbb00000000000000000000000000000000000000000000000000000000815286600482015285602482015282855af1601f3d11600160005114163d15171615611ee557505050565b60649350604051927fbf182be80000000000000000000000000000000000000000000000000000000084526001600160a01b0380921660048501521660248301526044820152fd5b90611f42575080511561184c57805190602001fd5b81511580611f8d575b611f53575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b15611f4b565b908060030b90600082126000146123475760000360030b5b63ffffffff80809416911602918216828103611d4e576204eb4a106123165760018216156122ed5770ffffffffffffffffffffffffffffffffff6ffffcb933bd6fad9d3af5f0b9f25db4d65b1690600283166122d1575b600483166122b5575b60088316612299575b6010831661227d575b60208316612261575b60408316612245575b60809283811661222a575b610100811661220f575b61020081166121f4575b61040081166121d9575b61080081166121be575b61100081166121a3575b6120008116612188575b614000811661216d575b6180008116612152575b620100008116612137575b62020000811661211c575b6204000016612102575b6000126120c4575b670de0b6b3a764000002901c90565b80156120d357600019046120b5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6d2216e584f630389b2052b8db590e909102821c906120ad565b6e5d6af8dedbcb3a6ccb7ce618d14225909202831c916120a3565b916f09aa508b5b7e5a9780b0cc4e25d61a5602831c91612098565b916f31be135f97da6e09a19dc367e3b6da4002831c9161208d565b916f70d869a156ddd32a39e257bc3f50aa9b02831c91612083565b916fa9f746462d8f7dd10e744d913d03333302831c91612079565b916fd097f3bdfd254ee83bdd3f248e7e785e02831c9161206f565b916fe7159475a2c578ef4f1d17b2b235d48002831c91612065565b916ff3392b0822b88206f8abe8a3b44dd9be02831c9161205b565b916ff987a7253ac4d9194200696907cf2e3702831c91612051565b916ffcbe86c7900aecf64236ab31f1f9dcb502831c91612047565b916ffe5dee046a99d51e2cc356c2f617dbe002831c9161203d565b906fff2ea16466c9838804e327cb417cafcb0260801c90612032565b906fff973b41fa98cd2e57b660be99eb2c4a0260801c90612029565b906fffcb9843d60f67b19e8887e0bd251eb70260801c90612020565b906fffe5caca7e10e81259b3cddc7a0649410260801c90612017565b906ffff2e50f5f656ac9229c67059486f3890260801c9061200e565b906ffff97272373d41fd789c8cb37ffcaa1c0260801c90612005565b70ffffffffffffffffffffffffffffffffff700100000000000000000000000000000000611ffa565b602490604051907f20ab18100000000000000000000000000000000000000000000000000000000082526004820152fd5b611fae565b9091928381039160009481604e1c158061241b575b61240a575b84156123fd5781156123c7576123bb6123c2956123b585876123b0633b9aca009661239b612394858b612490565b91876124be565b0160011c976123aa89806124dc565b956124dc565b61257b565b016125ff565b020161257b565b901c90565b6123d59150809392946124be565b90928082029281146123f4575b81830414901517156111dd5704901c90565b600193506123e2565b5090506123c29250612490565b6039955093851b9390851b90612366565b5084604e1c15612361565b9192939082156124885790818592156124805761245561245c9361246b9561244e88866124be565b0193612490565b0190612490565b670de0b6b3a7640000026125ff565b90818111908218021890818110908218021890565b505050505090565b505050905090565b670de0b6b3a7640000908181029183156124b5575b81830414901517156111dd570490565b600193506124a5565b8181029181830414901517156111dd57670de0b6b3a7640000900490565b90808202906000198184099082808310920391808303921461256a57670de0b6b3a76400009082821115612540577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b60046040517f227bc153000000000000000000000000000000000000000000000000000000008152fd5b5050670de0b6b3a764000091500490565b909182820291600019848209938380861095039480860395146125f157848311156125405782910981600003821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b5050809250156120d3570490565b60b581710100000000000000000000000000000000008110156126b4575b806901000000000000000000620100009210156126a7575b6501000000000081101561269a575b630100000081101561268d575b010260121c60019080830401811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c8080920410900390565b60101c9160081b91612651565b60201c9160101b91612644565b60401c9160201b91612635565b5068b500000000000000009050608082901c61261d56fea2646970667358221220463767556635a4cc7907ee65d20bb1c96747026a0ad612bf9e6054830facfd7364736f6c634300081900330000000000000000000000000a7e848aca42d879ef06507fca0e7b33a0a63c1e000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

Deployed Bytecode

0x60406080815260049081361015610074575b361561001c57600080fd5b6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216330361004e57005b517fc0f54629000000000000000000000000000000000000000000000000000000008152fd5b600060e08135811c90816312210e8a146110bc5781631841ad6d1461100157816319b871d314610f8157816328a5b3c914610ee75781633fc8cef314610ea357816349404b7c14610e83578163522ba7eb14610c3a578163670ca18114610b7f57816367ca7c911461095657816369b027ab146108dd578163a3b105ca146108be578163a4af5a7f146107fb578163a6990946146107aa578163ac9650d8146105f2578163b800a206146105a6578163b9e45300146101c557508063c45a01551461017d578063df2ab5bb1461016a5763f16d7904146101545750610011565b6101676101603661131c565b9091611e8d565b80f35b506101676101773661131c565b91611706565b5090346101c157816003193601126101c157602090516001600160a01b037f0000000000000000000000000a7e848aca42d879ef06507fca0e7b33a0a63c1e168152f35b5080fd5b8484849260606003193601126105a2576101dd611200565b91602435916001600160a01b03604435941682517f1865c57d00000000000000000000000000000000000000000000000000000000815261012080828981865afa90811561048357899161048d575b5060a09150015160030b908351927f3256cfa900000000000000000000000000000000000000000000000000000000845282888501528084602481855afa938415610483579088949392918a946103a1575b50506020908551948580927fd0c93a7c0000000000000000000000000000000000000000000000000000000082525afa92831561039757889361035d575b506102db8360016102d08461030997611f96565b930160030b90611f96565b906fffffffffffffffffffffffffffffffff602081855116940151166103038383838761234c565b93612426565b908282108015610354575b61031c578580f35b6064955051937ffcb505c700000000000000000000000000000000000000000000000000000000855284015260248301526044820152fd5b50838211610314565b92506020833d60201161038f575b8161037860209383611167565b8101031261038b579151916102db6102bc565b8780fd5b3d915061036b565b84513d8a823e3d90fd5b919450809293503d831161047c575b6103ba8183611167565b8101918082840312610478578551926103d2846110d0565b6103db83611e51565b84526020916103ec60208501611e51565b60208601526103fc888501611e51565b8886015281607f8501121561047457875193610417856110d0565b84918101928311610470579060608c9897969594939201905b828210610449575050505060608201529160208a61027e565b839495969798509281929361045e8293611e7c565b81520191018b97969594939291610430565b8c80fd5b8b80fd5b8980fd5b503d6103b0565b85513d8b823e3d90fd5b80915082813d831161059b575b6104a48183611167565b8101031261059757845190810181811067ffffffffffffffff82111761056b5785526104cf82611e51565b81526104dd60208301611e51565b60208201526104ed858301611e6e565b858201526104fd60608301611e6e565b6060820152608082015164ffffffffff8116810361047857608082015260a08201518060030b81036104785760a082015261053a60c083016114ff565b60c082015261054a848301611e7c565b848201526101008092015160ff811681036104785760a0928201528961022c565b60248a60418b7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b8880fd5b503d61049a565b8380fd5b505060a06003193601126105ef57506105e36105c0611200565b6105c8611216565b6105d061122c565b906105d9611281565b92606435916118a6565b82519182526020820152f35b80fd5b505082602091826003193601126105ef5781359167ffffffffffffffff908184116107a657366023850112156107a657830135908082116107a65760246005923660248260051b880101116107a2579261064b846116ab565b9561065889519788611167565b848752601f19610667866116ab565b0188875b8281106107925750505085917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd82360301925b868110610720578a8a8a8a83519280840190808552835180925280868601968360051b870101940192955b8287106106d65785850386f35b909192938280610710837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08a6001960301865288516112dc565b96019201960195929190926106c9565b8481831b84010135848112156105975783018581013590878211610478576044019080360382136104785789808d610760600196956107769536916111a6565b80519101305af461076f6117f3565b9030611f2d565b610780828c6116c3565b5261078b818b6116c3565b500161069e565b60608a82018301528a910161066b565b8480fd5b8280fd5b82858560206003193601126107a6578135908142116107c7578380f35b6044935051917f3442e977000000000000000000000000000000000000000000000000000000008352820152426024820152fd5b50508260c06003193601126101c157610872610815611200565b61081d611216565b9061082661122c565b9061082f611281565b60a4359688519361083f856110d0565b6064358552151560208501528884015260030b60608301528651923360208501526020845261086d8461111b565b611b8e565b91909280831061088a57505082519182526020820152f35b916044928551927f84ae11480000000000000000000000000000000000000000000000000000000084528301526024820152fd5b6020846108d66108cd3661123b565b9392909261150c565b9051908152f35b8261090885876108ec36611291565b9592908551926108fb8461111b565b8352336020840152611da7565b508354928084116109225750506000196020935551908152f35b604493919251927f4956866a0000000000000000000000000000000000000000000000000000000084528301526024820152fd5b505091346107a65760806003193601126107a657610972611200565b602480359260643567ffffffffffffffff80821161038b573660238301121561038b57818301359681881161059757848301948884019281840192368411610474578915610b57576001600160a01b039a8b978d8351809a7f578eaca40000000000000000000000000000000000000000000000000000000082523384830152818860209d8e937f0000000000000000000000000a7e848aca42d879ef06507fca0e7b33a0a63c1e165afa918215610b4c5791610b13575b5015610aec57508703610a57575050505003126107a257359283168093036105a257610167923391611985565b91939490929996868287031261047457358381116104745782910180950312610478575197610a858961111b565b8284013591821161047857604492610a9f928501016111e2565b9182885201359283169283810361038b576015928701525111600014610add57505090610ad991610ad08251611c75565b82523390611da7565b5080f35b61016793508285553391611985565b82517f36294ff5000000000000000000000000000000000000000000000000000000008152fd5b90508981813d8311610b45575b610b2a8183611167565b81010312610b4157610b3b906114ff565b38610a2a565b8e80fd5b503d610b20565b8551903d90823e3d90fd5b8690517f63fa284a000000000000000000000000000000000000000000000000000000008152fd5b8260806003193601126105ef57610b94611200565b610b9c611216565b90604435606435916001600160a01b03807f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216908181841614600014610bfe5750505090610bef61016793923390611363565b610bf7611350565b3391611706565b8592951614600014610c295750610c2192610c1a913391611706565b3390611363565b610167611350565b919061016793610bf7913391611706565b838584610c4636611291565b9195929390610c5487611902565b909182908215610e105786517f0fc63d100000000000000000000000000000000000000000000000000000000081526020818b816001600160a01b0389165afa908115610e0657610cc19183918891610dd7575b509b94959b5b6001600160a01b03809d16903390611985565b82516015811194908515610dc9576029809110610da15790610d299392918501518c16905b8015610d9557637fffffff905b8a5193610cff856110d0565b845215156020840152878a84015260030b6060830152885192610d218461114b565b878452611b8e565b92159050610d4d57610d3a90611c75565b96610d4488611902565b91989192610cc1565b50935050808310610d62576020838351908152f35b90517f84ae1148000000000000000000000000000000000000000000000000000000008152928301526024820152604490fd5b637fffffff1990610cf3565b8a89517f41a6c181000000000000000000000000000000000000000000000000000000008152fd5b5090610d2992918990610ce6565b610df9915060203d602011610dff575b610df18183611167565b8101906114e0565b8d610ca8565b503d610de7565b88513d88823e3d90fd5b86517f5f64b55b0000000000000000000000000000000000000000000000000000000081526020818b816001600160a01b0389165afa908115610e0657610cc19183918891610e64575b509b94959b610cae565b610e7d915060203d602011610dff57610df18183611167565b8d610e5a565b8285856003193601126101c15761016790610e9c611216565b9035611363565b8284346101c157816003193601126101c157602090516001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2168152f35b849291506003193601126105ef5750610efe611200565b610f06611216565b91610f2c610f1261122c565b610f1a611281565b9060a4359560c43595606435916118a6565b929093808511610f4c575080831061088a57505082519182526020820152f35b82856044928851927f4956866a0000000000000000000000000000000000000000000000000000000084528301526024820152fd5b505082610fa8610f903661123b565b965091929091908215610ff557637fffffff936118a6565b919092808411610fc057505082519182526020820152f35b90836044928651927f4956866a0000000000000000000000000000000000000000000000000000000084528301526024820152fd5b637fffffff19936118a6565b505060206003193601126105ef5782359067ffffffffffffffff82116105ef575061102f90369084016111e2565b91825160498103611088576020836108d68660148101516001600160a01b0360288301518116602984015192600160ff603987015160496fffffffffffffffffffffffffffffffff98015188169716951614921661150c565b60449251917fd137d34b00000000000000000000000000000000000000000000000000000000835282015260496024820152fd5b82806003193601126105ef57610167611350565b6080810190811067ffffffffffffffff8211176110ec57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040810190811067ffffffffffffffff8211176110ec57604052565b67ffffffffffffffff81116110ec57604052565b6020810190811067ffffffffffffffff8211176110ec57604052565b90601f601f19910116810190811067ffffffffffffffff8211176110ec57604052565b67ffffffffffffffff81116110ec57601f01601f191660200190565b9291926111b28261118a565b916111c06040519384611167565b8294818452818301116111dd578281602093846000960137010152565b600080fd5b9080601f830112156111dd578160206111fd933591016111a6565b90565b600435906001600160a01b03821682036111dd57565b602435906001600160a01b03821682036111dd57565b6044359081151582036111dd57565b60031960a09101126111dd576001600160a01b039060043582811681036111dd579160243590811681036111dd579060443580151581036111dd57906064359060843590565b608435908160030b82036111dd57565b9060806003198301126111dd576004356001600160a01b03811681036111dd57916024359067ffffffffffffffff82116111dd576112d1916004016111e2565b906044359060643590565b919082519283825260005b848110611308575050601f19601f8460006020809697860101520116010190565b6020818301810151848301820152016112e7565b60031960609101126111dd576001600160a01b0360043581811681036111dd57916024359160443590811681036111dd5790565b4761135757565b6113614733611823565b565b6001600160a01b03807f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21692604051927f70a08231000000000000000000000000000000000000000000000000000000008452306004850152602084602481885afa938415611457576000946114ac575b508084106114635750826113e9575b50505050565b833b156111dd57600080946024604051809781937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528860048401525af19384156114575761143f94611448575b5016611823565b388080806113e3565b61145190611137565b38611438565b6040513d6000823e3d90fd5b6040517fd1cd07af0000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602481019190915260448101849052606490fd5b90936020823d6020116114d8575b816114c760209383611167565b810103126105ef57505192386113d4565b3d91506114ba565b908160209103126111dd57516001600160a01b03811681036111dd5790565b519081151582036111dd57565b93949391929091831561163657604051937f0fc63d100000000000000000000000000000000000000000000000000000000085526020856004816001600160a01b0388165afa8015611457578361157d916115c597600091611617575b505b6001600160a01b038716903390611985565b801561160b57637fffffff905b60405193611597856110d0565b8452151560208401526000604084015260030b6060830152604051926115bc8461114b565b60008452611b8e565b929050828181106115d4575050565b60449250604051917f84ae114800000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b637fffffff199061158a565b611630915060203d602011610dff57610df18183611167565b38611569565b604051937f5f64b55b0000000000000000000000000000000000000000000000000000000085526020856004816001600160a01b0388165afa8015611457578361157d916115c59760009161168c575b5061156b565b6116a5915060203d602011610dff57610df18183611167565b38611686565b67ffffffffffffffff81116110ec5760051b60200190565b80518210156116d75760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b916001600160a01b03831691604051927f70a08231000000000000000000000000000000000000000000000000000000008452306004850152602084602481845afa938415611457576000946117bf575b508184106117745750508161176b57505050565b61136192611e8d565b6040517fd1cd07af0000000000000000000000000000000000000000000000000000000081526001600160a01b03919091166004820152602481019190915260448101839052606490fd5b90936020823d6020116117eb575b816117da60209383611167565b810103126105ef5750519238611757565b3d91506117cd565b3d1561181e573d906118048261118a565b916118126040519384611167565b82523d6000602084013e565b606090565b8147106118765760008080936001600160a01b038294165af16118446117f3565b501561184c57565b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b60246040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152fd5b92936118f994604051936118b9856110d0565b8452151560208401526001604084015260030b60608301526001600160a01b0381166118fd5750305b604051923360208501526020845261086d8461111b565b9091565b6118e2565b90601482511061195b5760148201516001600160a01b0316916015815110611931576015015160ff1660011490565b60046040517f7c1be900000000000000000000000000000000000000000000000000000000008152fd5b60046040517f41a6c181000000000000000000000000000000000000000000000000000000008152fd5b9190916001600160a01b039081811690827f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2169485831480611b84575b15611ac357505050823b156111dd57604051917fd0e30db0000000000000000000000000000000000000000000000000000000008352600092838160048189895af18015611ab857611aa1575b50604490836020949560405197889586947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af18015611a9457611a5e575050565b6020823d602011611a8c575b81611a7760209383611167565b810103126105ef5750611a89906114ff565b50565b3d9150611a6a565b50604051903d90823e3d90fd5b90602093611ab0604493611137565b935090611a0f565b6040513d86823e3d90fd5b91959450919081811690308203611ae1575050506113619350611e8d565b606460009182602094959796604051927f23b872dd00000000000000000000000000000000000000000000000000000000845260048401528760248401528960448401525af1601f3d11600160005114163d15171615611b42575050505050565b60849550604051947fa8dced90000000000000000000000000000000000000000000000000000000008652600486015260248501521660448301526064820152fd5b50864710156119c2565b9260609192611c11946001600160a01b03809560409788958651978896879586957f3eece7db000000000000000000000000000000000000000000000000000000008752166004860152805160248601526020810151151560448601528881015115156064860152015160030b608484015260c060a484015260c48301906112dc565b03916000968791165af1918215611c6a5780938193611c32575b5050509091565b919350915082813d8111611c63575b611c4b8183611167565b810103126105ef575060208151910151388080611c2b565b503d611c41565b8351903d90823e3d90fd5b8051907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb91828101818111611d4e57601f1992838211611d7d57805183601511611d4e578311611d245781611cda575050505050604051600081526020810160405290565b9190601560405195601f8316801560051b9182828a01019586010195010101925b808310611d115750601f92508452011660405290565b8351835260209384019390920191611cfb565b60046040517f326b3d3a000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60046040517f648fb3b1000000000000000000000000000000000000000000000000000000008152fd5b611e3992916001600160a01b0380821615611e49575b61086d611dca8551611902565b9092908015611e3d57637fffffff905b60405196611de7886110d0565b8752151560208701526001604087015260030b60608601526040519586916020808401526020611e22835160408087015260808601906112dc565b92015116606083015203601f198101865285611167565b5090565b637fffffff1990611dda565b309150611dbd565b51906fffffffffffffffffffffffffffffffff821682036111dd57565b51908160070b82036111dd57565b519063ffffffff821682036111dd57565b9190916020600060446040517fa9059cbb00000000000000000000000000000000000000000000000000000000815286600482015285602482015282855af1601f3d11600160005114163d15171615611ee557505050565b60649350604051927fbf182be80000000000000000000000000000000000000000000000000000000084526001600160a01b0380921660048501521660248301526044820152fd5b90611f42575080511561184c57805190602001fd5b81511580611f8d575b611f53575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b15611f4b565b908060030b90600082126000146123475760000360030b5b63ffffffff80809416911602918216828103611d4e576204eb4a106123165760018216156122ed5770ffffffffffffffffffffffffffffffffff6ffffcb933bd6fad9d3af5f0b9f25db4d65b1690600283166122d1575b600483166122b5575b60088316612299575b6010831661227d575b60208316612261575b60408316612245575b60809283811661222a575b610100811661220f575b61020081166121f4575b61040081166121d9575b61080081166121be575b61100081166121a3575b6120008116612188575b614000811661216d575b6180008116612152575b620100008116612137575b62020000811661211c575b6204000016612102575b6000126120c4575b670de0b6b3a764000002901c90565b80156120d357600019046120b5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6d2216e584f630389b2052b8db590e909102821c906120ad565b6e5d6af8dedbcb3a6ccb7ce618d14225909202831c916120a3565b916f09aa508b5b7e5a9780b0cc4e25d61a5602831c91612098565b916f31be135f97da6e09a19dc367e3b6da4002831c9161208d565b916f70d869a156ddd32a39e257bc3f50aa9b02831c91612083565b916fa9f746462d8f7dd10e744d913d03333302831c91612079565b916fd097f3bdfd254ee83bdd3f248e7e785e02831c9161206f565b916fe7159475a2c578ef4f1d17b2b235d48002831c91612065565b916ff3392b0822b88206f8abe8a3b44dd9be02831c9161205b565b916ff987a7253ac4d9194200696907cf2e3702831c91612051565b916ffcbe86c7900aecf64236ab31f1f9dcb502831c91612047565b916ffe5dee046a99d51e2cc356c2f617dbe002831c9161203d565b906fff2ea16466c9838804e327cb417cafcb0260801c90612032565b906fff973b41fa98cd2e57b660be99eb2c4a0260801c90612029565b906fffcb9843d60f67b19e8887e0bd251eb70260801c90612020565b906fffe5caca7e10e81259b3cddc7a0649410260801c90612017565b906ffff2e50f5f656ac9229c67059486f3890260801c9061200e565b906ffff97272373d41fd789c8cb37ffcaa1c0260801c90612005565b70ffffffffffffffffffffffffffffffffff700100000000000000000000000000000000611ffa565b602490604051907f20ab18100000000000000000000000000000000000000000000000000000000082526004820152fd5b611fae565b9091928381039160009481604e1c158061241b575b61240a575b84156123fd5781156123c7576123bb6123c2956123b585876123b0633b9aca009661239b612394858b612490565b91876124be565b0160011c976123aa89806124dc565b956124dc565b61257b565b016125ff565b020161257b565b901c90565b6123d59150809392946124be565b90928082029281146123f4575b81830414901517156111dd5704901c90565b600193506123e2565b5090506123c29250612490565b6039955093851b9390851b90612366565b5084604e1c15612361565b9192939082156124885790818592156124805761245561245c9361246b9561244e88866124be565b0193612490565b0190612490565b670de0b6b3a7640000026125ff565b90818111908218021890818110908218021890565b505050505090565b505050905090565b670de0b6b3a7640000908181029183156124b5575b81830414901517156111dd570490565b600193506124a5565b8181029181830414901517156111dd57670de0b6b3a7640000900490565b90808202906000198184099082808310920391808303921461256a57670de0b6b3a76400009082821115612540577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b60046040517f227bc153000000000000000000000000000000000000000000000000000000008152fd5b5050670de0b6b3a764000091500490565b909182820291600019848209938380861095039480860395146125f157848311156125405782910981600003821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b5050809250156120d3570490565b60b581710100000000000000000000000000000000008110156126b4575b806901000000000000000000620100009210156126a7575b6501000000000081101561269a575b630100000081101561268d575b010260121c60019080830401811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c8080920410900390565b60101c9160081b91612651565b60201c9160101b91612644565b60401c9160201b91612635565b5068b500000000000000009050608082901c61261d56fea2646970667358221220463767556635a4cc7907ee65d20bb1c96747026a0ad612bf9e6054830facfd7364736f6c63430008190033

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

0000000000000000000000000a7e848aca42d879ef06507fca0e7b33a0a63c1e000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

-----Decoded View---------------
Arg [0] : _factory (address): 0x0A7e848Aca42d879EF06507Fca0E7b33A0a63c1e
Arg [1] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

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


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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