ETH Price: $2,943.84 (-0.47%)
 

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Multicall242732502025-11-03 16:07:1282 days ago1762186032IN
Maverick V2: Position
0 ETH0.00000130.0001201
Multicall240171402025-10-29 20:28:1287 days ago1761769692IN
Maverick V2: Position
0 ETH0.000000050.0001201
Multicall236160432025-10-21 21:16:0295 days ago1761081362IN
Maverick V2: Position
0 ETH0.000000060.0001201
Multicall202642782025-08-28 19:11:11149 days ago1756408271IN
Maverick V2: Position
0 ETH0.00000160.01
Multicall192304352025-08-15 6:18:06162 days ago1755238686IN
Maverick V2: Position
0 ETH0.000000080.000202
Multicall189313102025-08-11 14:41:47166 days ago1754923307IN
Maverick V2: Position
0 ETH0.000000040.00013404
Multicall171317992025-07-11 13:35:57197 days ago1752240957IN
Maverick V2: Position
0 ETH0.000012250.03
Multicall171317482025-07-11 13:34:53197 days ago1752240893IN
Maverick V2: Position
0 ETH0.000011320.03
Multicall162431862025-06-05 13:42:49233 days ago1749130969IN
Maverick V2: Position
0 ETH0.000008470.01888048
Multicall161244132025-05-31 10:03:12238 days ago1748685792IN
Maverick V2: Position
0 ETH0.000015870.05
Multicall161243772025-05-31 10:01:39238 days ago1748685699IN
Maverick V2: Position
0 ETH0.000009530.03
Multicall158670892025-05-24 7:34:32245 days ago1748072072IN
Maverick V2: Position
0 ETH0.000009890.0251875
Multicall158670512025-05-24 7:33:05245 days ago1748071985IN
Maverick V2: Position
0 ETH0.00001190.0303
Multicall156639092025-05-20 7:04:58249 days ago1747724698IN
Maverick V2: Position
0 ETH0.000006410.01570053
Multicall156639082025-05-20 7:04:57249 days ago1747724697IN
Maverick V2: Position
0 ETH0.000006420.01570053
Multicall154788152025-05-15 7:39:45254 days ago1747294785IN
Maverick V2: Position
0 ETH0.000006820.0165534
Multicall154788122025-05-15 7:39:42254 days ago1747294782IN
Maverick V2: Position
0 ETH0.000006570.0165534
Multicall154788112025-05-15 7:39:41254 days ago1747294781IN
Maverick V2: Position
0 ETH0.000006820.0165534
Multicall154788102025-05-15 7:39:40254 days ago1747294780IN
Maverick V2: Position
0 ETH0.000006820.0165534
Multicall154788102025-05-15 7:39:40254 days ago1747294780IN
Maverick V2: Position
0 ETH0.000006820.0165534
Multicall154788092025-05-15 7:39:39254 days ago1747294779IN
Maverick V2: Position
0 ETH0.000009520.0231724
Multicall154788092025-05-15 7:39:39254 days ago1747294779IN
Maverick V2: Position
0 ETH0.000009160.0231724
Multicall154788092025-05-15 7:39:39254 days ago1747294779IN
Maverick V2: Position
0 ETH0.000009520.0231724
Multicall154788092025-05-15 7:39:39254 days ago1747294779IN
Maverick V2: Position
0 ETH0.000009160.0231724
Multicall154783102025-05-15 7:28:33254 days ago1747294113IN
Maverick V2: Position
0 ETH0.000006560.0165686
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
73323622024-07-11 12:35:31562 days ago1720701331  Contract Creation0 ETH
Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MaverickV2Position

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 5500 runs

Other Settings:
paris EvmVersion
// 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 {IMaverickV2Factory} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Factory.sol";
import {IMaverickV2Pool} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Pool.sol";
import {Math} from "@maverick/v2-common/contracts/libraries/Math.sol";
import {Multicall} from "@maverick/v2-common/contracts/base/Multicall.sol";
import {ONE} from "@maverick/v2-common/contracts/libraries/Constants.sol";
import {ArrayOperations} from "@maverick/v2-common/contracts/libraries/ArrayOperations.sol";

import {IMaverickV2Position} from "./interfaces/IMaverickV2Position.sol";
import {IPositionImage} from "./interfaces/IPositionImage.sol";

import {PoolInspection} from "./libraries/PoolInspection.sol";
import {Nft, INft} from "./positionbase/Nft.sol";
import {MigrateBins} from "./base/MigrateBins.sol";
import {Checks} from "./base/Checks.sol";

/**
 * @notice ERC-721 contract that stores user NFTs that contain Maverick V2 pool
 * liquidity.
 *
 * @dev The Maverick V2 pool has a concept of storing liquidity according to an
 * address and a "subaccount".  When liquidity is minted to an NFT, it is
 * stored in the pool to the address of this Position contract to the
 * subaccount that corresponds to the NFT tokenId.  The mechanism of liquidity
 * management is that the tokenId owner is the only user who can remove pool
 * liquidity in the subaccount corresponding to their tokenId.
 *
 * @dev Additionally, this position NFT has data about the pools and binIds
 * that a given tokenId has liquidity in. But these binId/pool values are
 * essentially self reported and can be updated by the token owner by calling
 * setTokenIdData.
 */
contract MaverickV2Position is Nft, Checks, MigrateBins, Multicall, IMaverickV2Position {
    using Cast for uint256;
    using ArrayOperations for uint32[];

    IPositionImage public immutable positionImage;
    IMaverickV2Factory public immutable factory;

    mapping(uint256 => PositionPoolBinIds[]) private dataByTokenId;

    constructor(IPositionImage _positionImage, IMaverickV2Factory _factory) Nft("Maverick v2 Position", "MPv2") {
        factory = _factory;
        positionImage = _positionImage;
    }

    /// @inheritdoc IMaverickV2Position
    function mint(address recipient, IMaverickV2Pool pool, uint32[] memory binIds) public returns (uint256 tokenId) {
        tokenId = _mint(recipient);
        PositionPoolBinIds memory data = PositionPoolBinIds(pool, binIds);
        _checkData(data);
        dataByTokenId[tokenId].push(data);
        emit PositionSetData(tokenId, 0, data);
    }

    /// @inheritdoc IMaverickV2Position
    function removeLiquidity(
        uint256 tokenId,
        address recipient,
        IMaverickV2Pool pool,
        IMaverickV2Pool.RemoveLiquidityParams memory params
    ) external onlyTokenIdAuthorizedUser(tokenId) returns (uint256 tokenAAmount, uint256 tokenBAmount) {
        (tokenAAmount, tokenBAmount) = pool.removeLiquidity(recipient, tokenId, params);
    }

    /// @inheritdoc IMaverickV2Position
    function removeLiquidityToSender(
        uint256 tokenId,
        IMaverickV2Pool pool,
        IMaverickV2Pool.RemoveLiquidityParams memory params
    ) external onlyTokenIdAuthorizedUser(tokenId) returns (uint256 tokenAAmount, uint256 tokenBAmount) {
        (tokenAAmount, tokenBAmount) = pool.removeLiquidity(msg.sender, tokenId, params);
    }

    /// @inheritdoc IMaverickV2Position
    function setTokenIdData(
        uint256 tokenId,
        uint256 index,
        IMaverickV2Pool pool,
        uint32[] memory binIds
    ) external onlyTokenIdAuthorizedUser(tokenId) {
        PositionPoolBinIds memory data = PositionPoolBinIds(pool, binIds);
        _checkData(data);
        dataByTokenId[tokenId][index] = data;
        _checkNoDuplicatePool(tokenId);
        emit PositionSetData(tokenId, index, data);
    }

    /// @inheritdoc IMaverickV2Position
    function setTokenIdData(
        uint256 tokenId,
        PositionPoolBinIds[] memory data
    ) external onlyTokenIdAuthorizedUser(tokenId) {
        delete dataByTokenId[tokenId];
        emit PositionClearData(tokenId);
        for (uint256 k; k < data.length; k++) {
            _checkData(data[k]);
            dataByTokenId[tokenId].push(data[k]);
            emit PositionSetData(tokenId, k, data[k]);
        }
        _checkNoDuplicatePool(tokenId);
    }

    /// @inheritdoc IMaverickV2Position
    function appendTokenIdData(
        uint256 tokenId,
        IMaverickV2Pool pool,
        uint32[] memory binIds
    ) external onlyTokenIdAuthorizedUser(tokenId) {
        PositionPoolBinIds memory data = PositionPoolBinIds(pool, binIds);
        _checkData(data);
        dataByTokenId[tokenId].push(data);
        _checkNoDuplicatePool(tokenId);
        emit PositionSetData(tokenId, dataByTokenId[tokenId].length - 1, data);
    }

    /// @inheritdoc IMaverickV2Position
    function getTokenIdData(uint256 tokenId) external view returns (PositionPoolBinIds[] memory) {
        return dataByTokenId[tokenId];
    }

    /// @inheritdoc IMaverickV2Position
    function getTokenIdData(uint256 tokenId, uint256 index) external view returns (PositionPoolBinIds memory) {
        return dataByTokenId[tokenId][index];
    }

    /// @inheritdoc IMaverickV2Position
    function tokenIdDataLength(uint256 tokenId) external view returns (uint256 length) {
        return dataByTokenId[tokenId].length;
    }

    /// @inheritdoc IMaverickV2Position
    function tokenIdPositionInformation(
        uint256 tokenId,
        uint256 startIndex,
        uint256 stopIndex
    ) public view returns (PositionFullInformation[] memory output) {
        stopIndex = Math.min(dataByTokenId[tokenId].length, stopIndex);
        uint256 count = stopIndex - startIndex;
        output = new PositionFullInformation[](count);
        for (uint256 k; k < count; k++) {
            uint256 index = k + startIndex;
            output[index] = tokenIdPositionInformation(tokenId, index);
        }
    }

    /// @inheritdoc IMaverickV2Position
    function tokenIdPositionInformation(
        uint256 tokenId,
        uint256 index
    ) public view returns (PositionFullInformation memory output) {
        output.poolBinIds = dataByTokenId[tokenId][index];
        (
            output.amountA,
            output.amountB,
            output.binAAmounts,
            output.binBAmounts,
            output.ticks,
            output.liquidities
        ) = PoolInspection.subaccountPositionInformation(
            output.poolBinIds.pool,
            address(this),
            tokenId,
            output.poolBinIds.binIds
        );
    }

    /// @inheritdoc IMaverickV2Position
    function getRemoveParams(
        uint256 tokenId,
        uint256 index,
        uint256 proportionD18
    ) public view returns (IMaverickV2Pool.RemoveLiquidityParams memory params) {
        PositionPoolBinIds memory data = dataByTokenId[tokenId][index];
        params.binIds = data.binIds;
        params.amounts = PoolInspection.binLpBalances(data.pool, params.binIds, tokenId);
        if (proportionD18 < ONE) {
            for (uint256 k; k < params.amounts.length; k++) {
                params.amounts[k] = Math.mulFloor(params.amounts[k], proportionD18).toUint128();
            }
        }
    }

    /**
     * @notice Checks that binIds are unique.
     */
    function _checkData(PositionPoolBinIds memory data) internal view {
        uint256 binCount = data.pool.getState().binCounter;
        // if not factory pool, revert
        // if permissioned liquidity, revert
        if (!factory.isFactoryPool(data.pool)) revert PositionNotFactoryPool();
        if (data.pool.permissionedLiquidity()) revert PositionPermissionedLiquidityPool();
        data.binIds.checkUnique(binCount);
    }

    /**
     * @notice Checks that token data does not contain duplicate pool.
     */
    function _checkNoDuplicatePool(uint256 tokenId) internal view {
        uint256 length = dataByTokenId[tokenId].length;
        if (length <= 1) return;
        // hold list of pools as they are pulled from storage
        IMaverickV2Pool[] memory poolList = new IMaverickV2Pool[](length);
        for (uint256 k; k < length; k++) {
            poolList[k] = dataByTokenId[tokenId][k].pool;
            for (uint256 j; j < k; j++) {
                // loop through all pools so far to compare to this new pool in the list
                if (poolList[k] == poolList[j]) revert PositionDuplicatePool(k, poolList[k]);
            }
        }
    }

    function tokenURI(uint256 tokenId) public view virtual override(Nft, INft) returns (string memory) {
        address owner = ownerOf(tokenId);
        return positionImage.image(tokenId, owner);
    }

    function name() public view override(INft, Nft) returns (string memory) {
        return super.name();
    }

    function symbol() public view override(INft, Nft) returns (string memory) {
        return super.symbol();
    }
}

// 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 IMulticall {
    function multicall(bytes[] calldata data) external returns (bytes[] memory results);
}

File 3 of 35 : Multicall.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 {IMulticall} from "./IMulticall.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

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

/*
 * @notice Multicall
 */
abstract contract Multicall is IMulticall {
    /**
     * @notice 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 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]);
        }
    }
}

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

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

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

library ArrayOperations {
    error ArrayElementsNotUnique(uint256 index, uint256 duplicateEntry);

    /**
     * @notice Checks that array of numbers are unique.
     * @param array Array of numbers to check.
     * @param maxArrayElementValue Maximum value possible in Array.
     */
    function checkUnique(uint32[] memory array, uint256 maxArrayElementValue) internal pure {
        // for pool with few bins (less than ~100k), the bitmap approach is
        // more gas efficient than exhaustive search of a 10-bin list.  As the
        // bin count in a pool grows beyond this, the gas cost of the bitmap
        // memory allocation quickly overtakes the exhaustive search cost.
        if (maxArrayElementValue < 100_000) {
            // allocate bitmap and set indexes to check uniqueness
            checkUniqueViaBitMap(array, maxArrayElementValue);
        } else {
            // search to check uniqueness
            checkUniqueViaSearch(array);
        }
    }

    /**
     * @notice Search all pair-wise combinations; low memory, but quadratic
     * comparison cost.
     */
    function checkUniqueViaSearch(uint32[] memory array) internal pure {
        uint256 length = array.length;
        if (length <= 1) return;
        for (uint256 i = 0; i < length - 1; i++) {
            for (uint256 j = i + 1; j < length; j++) {
                if (array[i] == array[j]) revert ArrayElementsNotUnique(j, array[j]);
            }
        }
    }

    /**
     * @notice Fill bitmap with values and revert on collision; memory is
     * proportional to pool bin count while comparison costs are linear in
     * array length.
     */
    function checkUniqueViaBitMap(uint32[] memory array, uint256 maxArrayElementValue) internal pure {
        uint256 length = array.length;
        if (length <= 1) return;
        uint256[] memory bitMap = new uint256[]((maxArrayElementValue >> 8) + 1);
        for (uint256 i; i < length; i++) {
            if (get(bitMap, array[i])) revert ArrayElementsNotUnique(i, array[i]);
            set(bitMap, array[i]);
        }
    }

    /**
     * @notice Gets the bit at `index`.
     */
    function get(uint256[] memory bitmap, uint256 index) private pure returns (bool) {
        uint256 bucket = index >> 8;
        uint256 mask = 1 << (index & 0xff);
        return bitmap[bucket] & mask != 0;
    }

    /**
     * @notice Sets the bit at `index`.
     */
    function set(uint256[] memory bitmap, uint256 index) private pure {
        uint256 bucket = index >> 8;
        uint256 mask = 1 << (index & 0xff);
        bitmap[bucket] |= mask;
    }
}

File 7 of 35 : 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";

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

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

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

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

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

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

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

interface IMigrateBins {
    function migrateBinsUpStack(IMaverickV2Pool pool, uint32[] calldata binIds, uint32 maxRecursion) external payable;
}

File 14 of 35 : MigrateBins.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 {IMigrateBins} from "./IMigrateBins.sol";

abstract contract MigrateBins is IMigrateBins {
    /**
     * @dev Migrates bins up the stack in the pool.
     * @param pool The MaverickV2Pool contract.
     * @param binIds An array of bin IDs to migrate.
     * @param maxRecursion The maximum recursion depth.
     */
    function migrateBinsUpStack(IMaverickV2Pool pool, uint32[] memory binIds, uint32 maxRecursion) public payable {
        for (uint256 i = 0; i < binIds.length; i++) {
            pool.migrateBinUpStack(binIds[i], maxRecursion);
        }
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IMaverickV2Factory} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Factory.sol";
import {IMaverickV2Pool} from "@maverick/v2-common/contracts/interfaces/IMaverickV2Pool.sol";
import {IMulticall} from "@maverick/v2-common/contracts/base/IMulticall.sol";
import {IPositionImage} from "./IPositionImage.sol";
import {INft} from "../positionbase/INft.sol";
import {IMigrateBins} from "../base/IMigrateBins.sol";
import {IChecks} from "../base/IChecks.sol";

interface IMaverickV2Position is INft, IMigrateBins, IMulticall, IChecks {
    event PositionClearData(uint256 indexed tokenId);
    event PositionSetData(uint256 indexed tokenId, uint256 index, PositionPoolBinIds newData);

    error PositionDuplicatePool(uint256 index, IMaverickV2Pool pool);
    error PositionNotFactoryPool();
    error PositionPermissionedLiquidityPool();

    struct PositionPoolBinIds {
        IMaverickV2Pool pool;
        uint32[] binIds;
    }

    struct PositionFullInformation {
        PositionPoolBinIds poolBinIds;
        uint256 amountA;
        uint256 amountB;
        uint256[] binAAmounts;
        uint256[] binBAmounts;
        int32[] ticks;
        uint256[] liquidities;
    }

    /**
     * @notice Contract that renders the position nft svg image.
     */
    function positionImage() external view returns (IPositionImage);

    /**
     * @notice Pool factory.
     */
    function factory() external view returns (IMaverickV2Factory);

    /**
     * @notice Mint NFT that holds liquidity in a Maverick V2 Pool. To mint
     * liquidity to an NFT, add liquidity to bins in a pool where the
     * add liquidity recipient is this contract and the subaccount is the
     * tokenId. LiquidityManager can be used to simplify minting Position NFTs.
     */
    function mint(address recipient, IMaverickV2Pool pool, uint32[] memory binIds) external returns (uint256 tokenId);

    /**
     * @notice Overwrites tokenId pool/binId information for a given data index.
     */
    function setTokenIdData(uint256 tokenId, uint256 index, IMaverickV2Pool pool, uint32[] memory binIds) external;

    /**
     * @notice Overwrites entire pool/binId data set for a given tokenId.
     */
    function setTokenIdData(uint256 tokenId, PositionPoolBinIds[] memory data) external;

    /**
     * @notice Append new pool/binIds data array to tokenId.
     */
    function appendTokenIdData(uint256 tokenId, IMaverickV2Pool pool, uint32[] memory binIds) external;

    /**
     * @notice Get array pool/binIds data for a given tokenId.
     */
    function getTokenIdData(uint256 tokenId) external view returns (PositionPoolBinIds[] memory);

    /**
     * @notice Get value from array of pool/binIds data for a given tokenId.
     */
    function getTokenIdData(uint256 tokenId, uint256 index) external view returns (PositionPoolBinIds memory);

    /**
     * @notice Length of array of pool/binIds data for a given tokenId.
     */
    function tokenIdDataLength(uint256 tokenId) external view returns (uint256 length);

    /**
     * @notice Remove liquidity from tokenId for a given pool.  User can
     * specify arbitrary bins to remove from for their subaccount in the pool
     * even if those bins are not in the tokenIdData set.
     */
    function removeLiquidity(
        uint256 tokenId,
        address recipient,
        IMaverickV2Pool pool,
        IMaverickV2Pool.RemoveLiquidityParams memory params
    ) external returns (uint256 tokenAAmount, uint256 tokenBAmount);

    /**
     * @notice Remove liquidity from tokenId for a given pool to sender.  User
     * can specify arbitrary bins to remove from for their subaccount in the
     * pool even if those bins are not in the tokenIdData set.
     */
    function removeLiquidityToSender(
        uint256 tokenId,
        IMaverickV2Pool pool,
        IMaverickV2Pool.RemoveLiquidityParams memory params
    ) external returns (uint256 tokenAAmount, uint256 tokenBAmount);

    /**
     * @notice NFT asset information for a given range of pool/binIds indexes.
     * This function only returns the liquidity in the pools/binIds stored as
     * part of the tokenIdData, but it is possible that the NFT has additional
     * liquidity in pools/binIds that have not been recorded.
     */
    function tokenIdPositionInformation(
        uint256 tokenId,
        uint256 startIndex,
        uint256 stopIndex
    ) external view returns (PositionFullInformation[] memory output);

    /**
     * @notice NFT asset information for a given pool/binIds index. This
     * function only returns the liquidity in the pools/binIds stored as part
     * of the tokenIdData, but it is possible that the NFT has additional
     * liquidity in pools/binIds that have not been recorded.
     */
    function tokenIdPositionInformation(
        uint256 tokenId,
        uint256 index
    ) external view returns (PositionFullInformation memory output);

    /**
     * @notice Get remove paramters for removing a fractional part of the
     * liquidity owned by a given tokenId.  The fractional factor to remove is
     * given by proporationD18 in 18-decimal scale.
     */
    function getRemoveParams(
        uint256 tokenId,
        uint256 index,
        uint256 proportionD18
    ) external view returns (IMaverickV2Pool.RemoveLiquidityParams memory params);
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {IMaverickV2Position} from "./IMaverickV2Position.sol";

interface IPositionImage {
    error PositionImageSetPositionError(address sender, address deployer, IMaverickV2Position currentPosition);

    function position() external view returns (IMaverickV2Position _position);
    function setPosition(IMaverickV2Position _position) external;
    function image(uint256 tokenId, address tokenOwner) external view returns (string memory);
}

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

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {IERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";

interface INft is IERC721Enumerable {
    /**
     * @notice Check if an NFT exists for a given owner and index.
     */
    function tokenOfOwnerByIndexExists(address owner, uint256 index) external view returns (bool);

    /**
     * @notice Return Id of the next token minted.
     */
    function nextTokenId() external view returns (uint256 nextTokenId_);

    /**
     * @notice Check if the caller has access to a specific NFT by tokenId.
     */
    function checkAuthorized(address spender, uint256 tokenId) external view returns (address owner);

    /**
     * @notice List of tokenIds by owner.
     */
    function tokenIdsOfOwner(address owner) external view returns (uint256[] memory tokenIds);

    /**
     * @notice Get the token URI for a given tokenId.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);

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

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;

import {ERC721, IERC165} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {ERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";

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

/**
 * @notice Extensions to ECR-721 to support an image contract and owner
 * enumeration.
 */
abstract contract Nft is ERC721Enumerable, INft {
    uint256 private _nextTokenId = 1;

    constructor(string memory __name, string memory __symbol) ERC721(__name, __symbol) {}

    /**
     * @notice Internal function to mint a new NFT and assign it to the
     * specified address.
     * @param to The address to which the NFT will be minted.
     * @return tokenId The ID of the newly minted NFT.
     */
    function _mint(address to) internal returns (uint256 tokenId) {
        super._mint(to, _nextTokenId);
        tokenId = _nextTokenId++;
    }

    /**
     * @notice Modifier to restrict access to functions to the owner of a
     * specific NFT by its tokenId.
     */
    modifier onlyTokenIdAuthorizedUser(uint256 tokenId) {
        checkAuthorized(msg.sender, tokenId);
        _;
    }

    /// @inheritdoc INft
    function nextTokenId() public view returns (uint256 nextTokenId_) {
        return _nextTokenId;
    }

    /// @inheritdoc INft
    function tokenOfOwnerByIndexExists(address ownerToCheck, uint256 index) public view returns (bool exists) {
        return index < balanceOf(ownerToCheck);
    }

    /// @inheritdoc INft
    function tokenIdsOfOwner(address owner) public view returns (uint256[] memory tokenIds) {
        uint256 tokenCount = balanceOf(owner);
        tokenIds = new uint256[](tokenCount);
        for (uint256 k; k < tokenCount; k++) {
            tokenIds[k] = tokenOfOwnerByIndex(owner, k);
        }
    }

    /// @inheritdoc INft
    function checkAuthorized(address spender, uint256 tokenId) public view returns (address owner) {
        owner = ownerOf(tokenId);
        _checkAuthorized(owner, spender, tokenId);
    }

    // ************************************************************
    // The following functions are overrides required by Solidity.

    function _update(address to, uint256 tokenId, address auth) internal override(ERC721Enumerable) returns (address) {
        return super._update(to, tokenId, auth);
    }

    function _increaseBalance(address account, uint128 value) internal override(ERC721Enumerable) {
        super._increaseBalance(account, value);
    }

    function name() public view virtual override(INft, ERC721) returns (string memory) {
        return super.name();
    }

    function symbol() public view virtual override(INft, ERC721) returns (string memory) {
        return super.symbol();
    }

    function supportsInterface(bytes4 interfaceId) public view override(ERC721Enumerable, IERC165) returns (bool) {
        return super.supportsInterface(interfaceId);
    }

    function tokenURI(uint256 tokenId) public view virtual override(INft, ERC721) returns (string memory) {
        return super.tokenURI(tokenId);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;

/**
 * @dev Standard ERC20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}

// 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 22 of 35 : ERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol)

pragma solidity ^0.8.20;

import {IERC721} from "./IERC721.sol";
import {IERC721Receiver} from "./IERC721Receiver.sol";
import {IERC721Metadata} from "./extensions/IERC721Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {Strings} from "../../utils/Strings.sol";
import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol";
import {IERC721Errors} from "../../interfaces/draft-IERC6093.sol";

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension, which is available separately as
 * {ERC721Enumerable}.
 */
abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors {
    using Strings for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    mapping(uint256 tokenId => address) private _owners;

    mapping(address owner => uint256) private _balances;

    mapping(uint256 tokenId => address) private _tokenApprovals;

    mapping(address owner => mapping(address operator => bool)) private _operatorApprovals;

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view virtual returns (uint256) {
        if (owner == address(0)) {
            revert ERC721InvalidOwner(address(0));
        }
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual returns (address) {
        return _requireOwned(tokenId);
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view virtual returns (string memory) {
        return _name;
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual returns (string memory) {
        _requireOwned(tokenId);

        string memory baseURI = _baseURI();
        return bytes(baseURI).length > 0 ? string.concat(baseURI, tokenId.toString()) : "";
    }

    /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
     * by default, can be overridden in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual {
        _approve(to, tokenId, _msgSender());
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view virtual returns (address) {
        _requireOwned(tokenId);

        return _getApproved(tokenId);
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC721-isApprovedForAll}.
     */
    function isApprovedForAll(address owner, address operator) public view virtual returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(address from, address to, uint256 tokenId) public virtual {
        if (to == address(0)) {
            revert ERC721InvalidReceiver(address(0));
        }
        // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists
        // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.
        address previousOwner = _update(to, tokenId, _msgSender());
        if (previousOwner != from) {
            revert ERC721IncorrectOwner(from, tokenId, previousOwner);
        }
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) public {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual {
        transferFrom(from, to, tokenId);
        _checkOnERC721Received(from, to, tokenId, data);
    }

    /**
     * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
     *
     * IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the
     * core ERC721 logic MUST be matched with the use of {_increaseBalance} to keep balances
     * consistent with ownership. The invariant to preserve is that for any address `a` the value returned by
     * `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`.
     */
    function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
        return _owners[tokenId];
    }

    /**
     * @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted.
     */
    function _getApproved(uint256 tokenId) internal view virtual returns (address) {
        return _tokenApprovals[tokenId];
    }

    /**
     * @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in
     * particular (ignoring whether it is owned by `owner`).
     *
     * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
     * assumption.
     */
    function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) {
        return
            spender != address(0) &&
            (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender);
    }

    /**
     * @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner.
     * Reverts if `spender` does not have approval from the provided `owner` for the given token or for all its assets
     * the `spender` for the specific `tokenId`.
     *
     * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
     * assumption.
     */
    function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual {
        if (!_isAuthorized(owner, spender, tokenId)) {
            if (owner == address(0)) {
                revert ERC721NonexistentToken(tokenId);
            } else {
                revert ERC721InsufficientApproval(spender, tokenId);
            }
        }
    }

    /**
     * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
     *
     * NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that
     * a uint256 would ever overflow from increments when these increments are bounded to uint128 values.
     *
     * WARNING: Increasing an account's balance using this function tends to be paired with an override of the
     * {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership
     * remain consistent with one another.
     */
    function _increaseBalance(address account, uint128 value) internal virtual {
        unchecked {
            _balances[account] += value;
        }
    }

    /**
     * @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner
     * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update.
     *
     * The `auth` argument is optional. If the value passed is non 0, then this function will check that
     * `auth` is either the owner of the token, or approved to operate on the token (by the owner).
     *
     * Emits a {Transfer} event.
     *
     * NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}.
     */
    function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) {
        address from = _ownerOf(tokenId);

        // Perform (optional) operator check
        if (auth != address(0)) {
            _checkAuthorized(from, auth, tokenId);
        }

        // Execute the update
        if (from != address(0)) {
            // Clear approval. No need to re-authorize or emit the Approval event
            _approve(address(0), tokenId, address(0), false);

            unchecked {
                _balances[from] -= 1;
            }
        }

        if (to != address(0)) {
            unchecked {
                _balances[to] += 1;
            }
        }

        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);

        return from;
    }

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal {
        if (to == address(0)) {
            revert ERC721InvalidReceiver(address(0));
        }
        address previousOwner = _update(to, tokenId, address(0));
        if (previousOwner != address(0)) {
            revert ERC721InvalidSender(address(0));
        }
    }

    /**
     * @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance.
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 tokenId) internal {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {
        _mint(to, tokenId);
        _checkOnERC721Received(address(0), to, tokenId, data);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     * This is an internal function that does not check if the sender is authorized to operate on the token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal {
        address previousOwner = _update(address(0), tokenId, address(0));
        if (previousOwner == address(0)) {
            revert ERC721NonexistentToken(tokenId);
        }
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(address from, address to, uint256 tokenId) internal {
        if (to == address(0)) {
            revert ERC721InvalidReceiver(address(0));
        }
        address previousOwner = _update(to, tokenId, address(0));
        if (previousOwner == address(0)) {
            revert ERC721NonexistentToken(tokenId);
        } else if (previousOwner != from) {
            revert ERC721IncorrectOwner(from, tokenId, previousOwner);
        }
    }

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients
     * are aware of the ERC721 standard to prevent tokens from being forever locked.
     *
     * `data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is like {safeTransferFrom} in the sense that it invokes
     * {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `tokenId` token must exist and be owned by `from`.
     * - `to` cannot be the zero address.
     * - `from` cannot be the zero address.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(address from, address to, uint256 tokenId) internal {
        _safeTransfer(from, to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual {
        _transfer(from, to, tokenId);
        _checkOnERC721Received(from, to, tokenId, data);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is
     * either the owner of the token, or approved to operate on all tokens held by this owner.
     *
     * Emits an {Approval} event.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address to, uint256 tokenId, address auth) internal {
        _approve(to, tokenId, auth, true);
    }

    /**
     * @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not
     * emitted in the context of transfers.
     */
    function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual {
        // Avoid reading the owner unless necessary
        if (emitEvent || auth != address(0)) {
            address owner = _requireOwned(tokenId);

            // We do not use _isAuthorized because single-token approvals should not be able to call approve
            if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) {
                revert ERC721InvalidApprover(auth);
            }

            if (emitEvent) {
                emit Approval(owner, to, tokenId);
            }
        }

        _tokenApprovals[tokenId] = to;
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Requirements:
     * - operator can't be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
        if (operator == address(0)) {
            revert ERC721InvalidOperator(operator);
        }
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned).
     * Returns the owner.
     *
     * Overrides to ownership logic should be done to {_ownerOf}.
     */
    function _requireOwned(uint256 tokenId) internal view returns (address) {
        address owner = _ownerOf(tokenId);
        if (owner == address(0)) {
            revert ERC721NonexistentToken(tokenId);
        }
        return owner;
    }

    /**
     * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the
     * recipient doesn't accept the token transfer. The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param data bytes optional data to send along with the call
     */
    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private {
        if (to.code.length > 0) {
            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
                if (retval != IERC721Receiver.onERC721Received.selector) {
                    revert ERC721InvalidReceiver(to);
                }
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert ERC721InvalidReceiver(to);
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Enumerable.sol)

pragma solidity ^0.8.20;

import {ERC721} from "../ERC721.sol";
import {IERC721Enumerable} from "./IERC721Enumerable.sol";
import {IERC165} from "../../../utils/introspection/ERC165.sol";

/**
 * @dev This implements an optional extension of {ERC721} defined in the EIP that adds enumerability
 * of all the token ids in the contract as well as all token ids owned by each account.
 *
 * CAUTION: `ERC721` extensions that implement custom `balanceOf` logic, such as `ERC721Consecutive`,
 * interfere with enumerability and should not be used together with `ERC721Enumerable`.
 */
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
    mapping(address owner => mapping(uint256 index => uint256)) private _ownedTokens;
    mapping(uint256 tokenId => uint256) private _ownedTokensIndex;

    uint256[] private _allTokens;
    mapping(uint256 tokenId => uint256) private _allTokensIndex;

    /**
     * @dev An `owner`'s token query was out of bounds for `index`.
     *
     * NOTE: The owner being `address(0)` indicates a global out of bounds index.
     */
    error ERC721OutOfBoundsIndex(address owner, uint256 index);

    /**
     * @dev Batch mint is not allowed.
     */
    error ERC721EnumerableForbiddenBatchMint();

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
        return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256) {
        if (index >= balanceOf(owner)) {
            revert ERC721OutOfBoundsIndex(owner, index);
        }
        return _ownedTokens[owner][index];
    }

    /**
     * @dev See {IERC721Enumerable-totalSupply}.
     */
    function totalSupply() public view virtual returns (uint256) {
        return _allTokens.length;
    }

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index) public view virtual returns (uint256) {
        if (index >= totalSupply()) {
            revert ERC721OutOfBoundsIndex(address(0), index);
        }
        return _allTokens[index];
    }

    /**
     * @dev See {ERC721-_update}.
     */
    function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) {
        address previousOwner = super._update(to, tokenId, auth);

        if (previousOwner == address(0)) {
            _addTokenToAllTokensEnumeration(tokenId);
        } else if (previousOwner != to) {
            _removeTokenFromOwnerEnumeration(previousOwner, tokenId);
        }
        if (to == address(0)) {
            _removeTokenFromAllTokensEnumeration(tokenId);
        } else if (previousOwner != to) {
            _addTokenToOwnerEnumeration(to, tokenId);
        }

        return previousOwner;
    }

    /**
     * @dev Private function to add a token to this extension's ownership-tracking data structures.
     * @param to address representing the new owner of the given token ID
     * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
     */
    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
        uint256 length = balanceOf(to) - 1;
        _ownedTokens[to][length] = tokenId;
        _ownedTokensIndex[tokenId] = length;
    }

    /**
     * @dev Private function to add a token to this extension's token tracking data structures.
     * @param tokenId uint256 ID of the token to be added to the tokens list
     */
    function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
        _allTokensIndex[tokenId] = _allTokens.length;
        _allTokens.push(tokenId);
    }

    /**
     * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
     * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
     * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
     * This has O(1) time complexity, but alters the order of the _ownedTokens array.
     * @param from address representing the previous owner of the given token ID
     * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
     */
    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
        // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = balanceOf(from);
        uint256 tokenIndex = _ownedTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary
        if (tokenIndex != lastTokenIndex) {
            uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];

            _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
            _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
        }

        // This also deletes the contents at the last position of the array
        delete _ownedTokensIndex[tokenId];
        delete _ownedTokens[from][lastTokenIndex];
    }

    /**
     * @dev Private function to remove a token from this extension's token tracking data structures.
     * This has O(1) time complexity, but alters the order of the _allTokens array.
     * @param tokenId uint256 ID of the token to be removed from the tokens list
     */
    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
        // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _allTokens.length - 1;
        uint256 tokenIndex = _allTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
        // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
        // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
        uint256 lastTokenId = _allTokens[lastTokenIndex];

        _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
        _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index

        // This also deletes the contents at the last position of the array
        delete _allTokensIndex[tokenId];
        _allTokens.pop();
    }

    /**
     * See {ERC721-_increaseBalance}. We need that to account tokens that were minted in batch
     */
    function _increaseBalance(address account, uint128 amount) internal virtual override {
        if (amount > 0) {
            revert ERC721EnumerableForbiddenBatchMint();
        }
        super._increaseBalance(account, amount);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Enumerable.sol)

pragma solidity ^0.8.20;

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

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {
    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.20;

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

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
     *   {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 27 of 35 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.20;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be
     * reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// 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 33 of 35 : 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);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

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

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = HEX_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
     * representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

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

API
[{"inputs":[{"internalType":"contract IPositionImage","name":"_positionImage","type":"address"},{"internalType":"contract IMaverickV2Factory","name":"_factory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"duplicateEntry","type":"uint256"}],"name":"ArrayElementsNotUnique","type":"error"},{"inputs":[],"name":"ERC721EnumerableForbiddenBatchMint","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"ERC721OutOfBoundsIndex","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"blockTimestamp","type":"uint256"}],"name":"PositionDeadlinePassed","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"}],"name":"PositionDuplicatePool","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":"PositionNotFactoryPool","type":"error"},{"inputs":[],"name":"PositionPermissionedLiquidityPool","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"int256","name":"tick","type":"int256"}],"name":"TickMaxExceeded","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"PositionClearData","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"components":[{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"uint32[]","name":"binIds","type":"uint32[]"}],"indexed":false,"internalType":"struct IMaverickV2Position.PositionPoolBinIds","name":"newData","type":"tuple"}],"name":"PositionSetData","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"uint32[]","name":"binIds","type":"uint32[]"}],"name":"appendTokenIdData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"checkAuthorized","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"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":[],"name":"factory","outputs":[{"internalType":"contract IMaverickV2Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"proportionD18","type":"uint256"}],"name":"getRemoveParams","outputs":[{"components":[{"internalType":"uint32[]","name":"binIds","type":"uint32[]"},{"internalType":"uint128[]","name":"amounts","type":"uint128[]"}],"internalType":"struct IMaverickV2Pool.RemoveLiquidityParams","name":"params","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getTokenIdData","outputs":[{"components":[{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"uint32[]","name":"binIds","type":"uint32[]"}],"internalType":"struct IMaverickV2Position.PositionPoolBinIds[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getTokenIdData","outputs":[{"components":[{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"uint32[]","name":"binIds","type":"uint32[]"}],"internalType":"struct IMaverickV2Position.PositionPoolBinIds","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"uint32[]","name":"binIds","type":"uint32[]"},{"internalType":"uint32","name":"maxRecursion","type":"uint32"}],"name":"migrateBinsUpStack","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"uint32[]","name":"binIds","type":"uint32[]"}],"name":"mint","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextTokenId","outputs":[{"internalType":"uint256","name":"nextTokenId_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"positionImage","outputs":[{"internalType":"contract IPositionImage","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"components":[{"internalType":"uint32[]","name":"binIds","type":"uint32[]"},{"internalType":"uint128[]","name":"amounts","type":"uint128[]"}],"internalType":"struct IMaverickV2Pool.RemoveLiquidityParams","name":"params","type":"tuple"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"tokenAAmount","type":"uint256"},{"internalType":"uint256","name":"tokenBAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"components":[{"internalType":"uint32[]","name":"binIds","type":"uint32[]"},{"internalType":"uint128[]","name":"amounts","type":"uint128[]"}],"internalType":"struct IMaverickV2Pool.RemoveLiquidityParams","name":"params","type":"tuple"}],"name":"removeLiquidityToSender","outputs":[{"internalType":"uint256","name":"tokenAAmount","type":"uint256"},{"internalType":"uint256","name":"tokenBAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"uint32[]","name":"binIds","type":"uint32[]"}],"name":"setTokenIdData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"uint32[]","name":"binIds","type":"uint32[]"}],"internalType":"struct IMaverickV2Position.PositionPoolBinIds[]","name":"data","type":"tuple[]"}],"name":"setTokenIdData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenIdDataLength","outputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"stopIndex","type":"uint256"}],"name":"tokenIdPositionInformation","outputs":[{"components":[{"components":[{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"uint32[]","name":"binIds","type":"uint32[]"}],"internalType":"struct IMaverickV2Position.PositionPoolBinIds","name":"poolBinIds","type":"tuple"},{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256[]","name":"binAAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"binBAmounts","type":"uint256[]"},{"internalType":"int32[]","name":"ticks","type":"int32[]"},{"internalType":"uint256[]","name":"liquidities","type":"uint256[]"}],"internalType":"struct IMaverickV2Position.PositionFullInformation[]","name":"output","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenIdPositionInformation","outputs":[{"components":[{"components":[{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"internalType":"uint32[]","name":"binIds","type":"uint32[]"}],"internalType":"struct IMaverickV2Position.PositionPoolBinIds","name":"poolBinIds","type":"tuple"},{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256[]","name":"binAAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"binBAmounts","type":"uint256[]"},{"internalType":"int32[]","name":"ticks","type":"int32[]"},{"internalType":"uint256[]","name":"liquidities","type":"uint256[]"}],"internalType":"struct IMaverickV2Position.PositionFullInformation","name":"output","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"tokenIdsOfOwner","outputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ownerToCheck","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndexExists","outputs":[{"internalType":"bool","name":"exists","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c03461036a576001600160401b03601f601f196149b0388190038381018316860191908583118784101761035457808792604094855283398101031261036a578351926001600160a01b0392838516850361036a57602080960151938416840361036a5761006c61036f565b92601484527f4d6176657269636b20763220506f736974696f6e0000000000000000000000008785015261009e61036f565b90600482526326a83b1960e11b88830152845190848211610354576000918254966001978881811c9116801561034a575b8c82101461033657908b82888594116102e5575b50508b9087831160011461028557859261027a575b5050600019600383901b1c191690871b1782555b82519485116102665785548681811c9116801561025c575b8a82101461024857848111610205575b50889385116001146101a4575083949596975092610199575b5050600019600383901b1c191690821b1781555b600a5560a052608052604051614621908161038f82396080518181816106e901526109af015260a051818181610aa301526136ff0152f35b01519050388061014d565b8493929193169785845280842093905b8982106101ee5750508385969798106101d5575b505050811b018155610161565b015160001960f88460031b161c191690553880806101c8565b8087859682949686015181550195019301906101b4565b8683528983208580880160051c8201928c891061023f575b0160051c019087905b828110610234575050610134565b848155018790610226565b9250819261021d565b634e487b7160e01b83526022600452602483fd5b90607f1690610124565b634e487b7160e01b82526041600452602482fd5b0151905038806100f8565b908c91858b95168780528388209388905b8282106102cc57505084116102b3575b505050811b01825561010c565b015160001960f88460031b161c191690553880806102a6565b8484015186558d97909501949384019390810190610296565b90919250858052878287209181860160051c830193861061032d575b918b91869594930160051c01915b82811061031f57508d91506100e3565b8781558594508b910161030f565b92508192610301565b634e487b7160e01b85526022600452602485fd5b90607f16906100cf565b634e487b7160e01b600052604160045260246000fd5b600080fd5b60408051919082016001600160401b038111838210176103545760405256fe60a060408181526004908136101561001657600080fd5b600092833560e01c90816301ffc9a714611e225750806306fdde0314611d55578063081812fc14611d1b578063095ea7b314611c1157806310c01fcd14611b1b57806318160ddd14611afc57806323b872dd14611ae45780632f745c5914611abb57806342842e0e14611a6c57806345d77f7e1461170a57806348fd65fe146116df5780634f6ccce7146116715780636352211e146116415780636621a76f146115a95780636f78d298146114d757806370a08231146114aa578063751df17a1461146757806375794a3c1461144857806378acef13146114205780637af50dff146113355780637fc3d351146112ef57806395d89b41146111b75780639e59e5981461114d578063a22cb4651461107a578063a58b083314610f4d578063a699094614610efe578063ac9650d814610d63578063b88d4fde14610cfe578063b9e4530014610ac7578063c45a015514610a83578063c87b56dd1461094e578063cc63c52f1461070d578063cd04b9cd146106c9578063d2d8a77014610695578063e05a807b14610593578063e985e9c514610541578063f66d8d4d146104665763f912f1da146101c657600080fd5b34610462578060031936011261046257813590602492833567ffffffffffffffff9182821161045e573660238301121561045e57818101359161020883612025565b9261021586519485612002565b808452602094888686019260051b8401019236841161045a57898101925b8484106103cc575050505050610252853361024d826134e2565b6139ac565b848752600b95600b84528488208054918982558261032e575b50505050837f7eec32dd7050b28720bc3a144a9b54740b810701816e7583f829ecf6dd6a83b48780a2855b815181101561032157806102b56102af60019385612bfa565b51613663565b8588528684526102d28589206102cb8386612bfa565b51906125d6565b857fdedccb02f6c0249f96cf577d6a79d5b7869c1effa31e4416b730a0d71b68720a6103186103018487612bfa565b5188519182918683528a8a8401528a8301906121d6565b0390a201610296565b8661032b86613898565b80f35b6001937f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841684036103bb57505088528388209060011b8101905b818110610376578061026b565b8881558281018054908a815581610392575b5050600201610369565b8a52836007878c20920160031c8201915b8281106103b05750610388565b8b81550184906103a3565b60118b91634e487b7160e01b835252fd5b8335838111610456578201897fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc82360301126104565789519161040e83611fb4565b8c8201356001600160a01b0381168103610452578352604482013592858411610452576104438b94938f86953692010161203d565b83820152815201930192610233565b8e80fd5b8c80fd5b8a80fd5b8680fd5b8280fd5b50903461046257608060031936011261046257803591602435610487611f9e565b926064359367ffffffffffffffff851161045e576104cc61053b927fdedccb02f6c0249f96cf577d6a79d5b7869c1effa31e4416b730a0d71b68720a9636910161203d565b6104da873361024d826134e2565b6001600160a01b038551926104ee84611fb4565b16825260208201526104ff81613663565b858752600b60205261051d8161051785878b206123c6565b906123f8565b61052686613898565b835193849384528060208501528301906121d6565b0390a280f35b83823461058f578060031936011261058f5760ff81602093610561611f6d565b610569611f88565b6001600160a01b0391821683526005875283832091168252855220549151911615158152f35b5080fd5b50906060600319360112610462576105a9611f6d565b916024936024359267ffffffffffffffff93848111610462576105cf903690830161203d565b93604480359063ffffffff8083168093036106915796976001600160a01b031696855b895181101561068d5781610606828c612bfa565b5116893b1561068957878c918589838e8a8f5197889687957f8e5430a70000000000000000000000000000000000000000000000000000000087528601528401525af1801561067f5761065d575b506001016105f2565b85811161066d5788526001610654565b8b88604189634e487b7160e01b835252fd5b89513d8a823e3d90fd5b8780fd5b8680f35b8580fd5b83823461058f576106c5906106b26106ac366121ff565b90612e20565b9051918291602083526020830190612263565b0390f35b83823461058f578160031936011261058f57602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b50913461094b57829061071f36612249565b84959195519261072e84611fb4565b606084526020936107586107528683019960608b52848952600b88528989206123c6565b50612990565b906001600160a01b038683015192838352511693601f19610791845161078961078082612025565b9c519c8d612002565b808c52612025565b0136888b0137875b83518110156108b05761080e888d63ffffffff6107b68589612bfa565b51169051809381927ff98175c40000000000000000000000000000000000000000000000000000000083528a8d3090850191604091949363ffffffff916001600160a01b036060860197168552602085015216910152565b03818a5afa9081156108a657908b92918b9161084d575b506fffffffffffffffffffffffffffffffff61084383600195612bfa565b9116905201610799565b809293508a8092503d831161089f575b6108678183612002565b8101031261089b57908a6fffffffffffffffffffffffffffffffff61084383610891600196613536565b9395505050610825565b8980fd5b503d61085d565b8d513d8c823e3d90fd5b508a87918b8a8c8252670de0b6b3a764000083106108df575b5050506106c59051928284938452830190612362565b94909291945b8351805182101561093a57908061092461091f896001956109186fffffffffffffffffffffffffffffffff958692612bfa565b5116613c7a565b613b72565b90610930838851612bfa565b91169052016108e5565b505093506106c591509084806108c9565b80fd5b50346104625760209182600319360112610a7f578381356044610970826134e2565b936001600160a01b0380875196879586947f1853083b0000000000000000000000000000000000000000000000000000000086528501521660248301527f0000000000000000000000000000000000000000000000000000000000000000165afa938415610a745780946109f4575b50506106c59051928284938452830190611f48565b909193503d8082843e610a078184612002565b820191838184031261058f5780519067ffffffffffffffff8211610462570182601f8201121561058f57805191610a3d8361230f565b93610a4a87519586612002565b83855285848401011161094b57508291610a6c9185806106c596019101611f25565b9290386109df565b8251903d90823e3d90fd5b8380fd5b83823461058f578160031936011261058f57602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b50606060031936011261046257610adc611f6d565b90602435906001600160a01b03604435931681517f1865c57d0000000000000000000000000000000000000000000000000000000081526101209081818881865afa918215610c93579060a092918992610cd1575b5050015160030b8251917f3256cfa9000000000000000000000000000000000000000000000000000000008352818784015260e083602481845afa928315610c935790879392918993610c9d575b506020908551948580927fd0c93a7c0000000000000000000000000000000000000000000000000000000082525afa928315610c93578893610c5d575b50610bdb836001610bd084610c0997613fd2565b930160030b90613fd2565b906fffffffffffffffffffffffffffffffff60208185511694015116610c0383838387614359565b93614410565b908282108015610c54575b610c1c578580f35b6064955051937ffcb505c700000000000000000000000000000000000000000000000000000000855284015260248301526044820152fd5b50838211610c14565b92506020833d602011610c8b575b81610c7860209383612002565b8101031261068957915191610bdb610bbc565b3d9150610c6b565b84513d8a823e3d90fd5b6020919350610cc39060e03d60e011610cca575b610cbb8183612002565b810190613ad7565b9290610b7f565b503d610cb1565b610cf09250803d10610cf7575b610ce88183612002565b81019061359b565b3880610b31565b503d610cde565b50503461058f57608060031936011261058f57610d19611f6d565b610d21611f88565b9060643567ffffffffffffffff8111610d5f5736602382011215610d5f5761032b93816024610d559336930135910161232b565b9160443591612c81565b8480fd5b5091903461058f576020918260031936011261094b5781359167ffffffffffffffff90818411610462573660238501121561046257830135908082116104625760246005923660248260051b88010111610d5f5792610dc184612025565b95610dce89519788612002565b848752601f19610ddd86612025565b0188875b828110610eee5750505085917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd82360301925b868110610e78578a8a8a8a83519280840190808552835180925280868601968360051b870101940192955b828710610e4c5785850386f35b909192938280610e6883603f198a600196030186528851611f48565b9601920196019592919092610e3f565b8481831b8401013584811215610eea578301858101359087821161089b5760440190803603821361089b5789808d610eb860019695610ece95369161232b565b80519101305af4610ec7613aa7565b9030613bc7565b610ed8828c612bfa565b52610ee3818b612bfa565b5001610e14565b8880fd5b60608a82018301528a9101610de1565b50602060031936011261046257813590814211610f19578380f35b6044935051917f3442e977000000000000000000000000000000000000000000000000000000008352820152426024820152fd5b5091903461058f57610f5e36612249565b9391808394929452602094600b865286842054908181109082180218918483039283116110675750610f8f82612025565b93610f9c87519586612002565b828552601f19610fab84612025565b0186855b82811061105157505050835b83811061101f575050505083519280840190808552835180925280868601968360051b870101940192955b828710610ff35785850386f35b90919293828061100f83603f198a600196030186528851612263565b9601920196019592919092610fe6565b8061104a61102f84600194612c5e565b6110398187612e20565b611043828b612bfa565b5288612bfa565b5001610fbb565b611059612c0e565b82828a010152018790610faf565b836011602492634e487b7160e01b835252fd5b5034610462578060031936011261046257611093611f6d565b9060243591821515809303610d5f576001600160a01b031692831561111f575033845260056020528084208385526020528084207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff8416179055519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b8360249251917f5b08ba18000000000000000000000000000000000000000000000000000000008352820152fd5b50823461094b57602060031936011261094b57611168611f6d565b9161117283612b5e565b61117b81612bc9565b925b818110611199578251602080825281906106c590820187612215565b806111a6600192876128a4565b6111b08287612bfa565b520161117d565b50823461094b578060031936011261094b5781519181600192600154938460011c91600186169586156112e5575b60209687851081146112d2578899509688969785829a52918260001461128d575050600114611231575b5050506106c59291611222910385612002565b51928284938452830190611f48565b9190869350600183527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b82841061127557505050820101816112226106c561120f565b8054848a01860152889550879490930192810161125c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168782015293151560051b8601909301935084925061122291506106c5905061120f565b60248360228c634e487b7160e01b835252fd5b92607f16926111e5565b83823461058f576113226107526106c5938361130a366121ff565b9290611314612baf565b508152600b602052206123c6565b90519182916020835260208301906121d6565b5091903461058f57606060031936011261058f578035611353611f88565b9060443567ffffffffffffffff8111610d5f57916113c79391856001600160a01b036113838996369087016120df565b94611392843361024d826134e2565b8651978896879586937ff957f1ca0000000000000000000000000000000000000000000000000000000085523390850161296b565b0393165af19081156114165782916113e7575b5082519182526020820152f35b90506114099150823d841161140f575b6114018183612002565b810190612955565b386113da565b503d6113f7565b83513d84823e3d90fd5b509034610462576020600319360112610462576020928291358152600b845220549051908152f35b83823461058f578160031936011261058f57602090600a549051908152f35b83823461058f578060031936011261058f576020906001600160a01b0361148c611f6d565b916114a360243561149c816134e2565b94856139ac565b5191168152f35b83823461058f57602060031936011261058f576020906114d06114cb611f6d565b612b5e565b9051908152f35b5091903461058f576020908160031936011261046257919091358152600b825282812090815461150681612025565b9061151386519283612002565b8082528482018094845285842084915b83831061158457505050508451938085019181865251809252858501958260051b8601019392955b8287106115585785850386f35b90919293828061157483603f198a6001960301865288516121d6565b960192019601959291909261154b565b600288600192611597859b98999b612990565b81520192019201919096949396611523565b5091903461058f57608060031936011261058f5780356115c7611f88565b6115cf611f9e565b9060643567ffffffffffffffff81116106915790856001600160a01b036115fc89969594369089016120df565b9661160b863361024d826134e2565b6113c78751988997889687947ff957f1ca000000000000000000000000000000000000000000000000000000008652850161296b565b50823461094b57602060031936011261094b57506001600160a01b03611669602093356134e2565b915191168152f35b509034610462576020600319360112610462578035926008548410156116ab5760208361169d8661291e565b91905490519160031b1c8152f35b604493919251927fa57d13dc0000000000000000000000000000000000000000000000000000000084528301526024820152fd5b83823461058f578060031936011261058f576020906116ff6114cb611f6d565b602435109051908152f35b503461046257606060031936011261046257611724611f6d565b9261172d611f88565b9060443567ffffffffffffffff811161058f5761174d903690860161203d565b600a54956001600160a01b03908181168015611a3d578885526020988992600284528489882054168381156002811597886119ed575b838c52600381528d8c2060018154019055868c52528b8a20827fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790558482847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8d80a415611966575060085483895260098d52808b8a205568010000000000000000811015611953579061183e8461182684600189960160085561291e565b90919060001983549160031b92831b921b1916179055565b03611905575b5050506118d657600a549560001987146110675750918593917fdedccb02f6c0249f96cf577d6a79d5b7869c1effa31e4416b730a0d71b68720a9360018601600a5586519361189285611fb4565b168352878301526118a282613663565b838152600b87526118b5828683206125d6565b6118cd855192839283528689840152868301906121d6565b0390a251908152f35b602486848751917f73c6ac6e000000000000000000000000000000000000000000000000000000008352820152fd5b61190e90612b5e565b91600019830192831161194057865260068a528786208287528a52808887205585526007895286852055388080611844565b60248760118c634e487b7160e01b835252fd5b60248960418e634e487b7160e01b835252fd5b908a8d838303611978575b505061183e565b6006908b61198585612b5e565b9388825260078352808220548581036119b8575b50888252812055838c52528b8a20908a528d52888b8120558a8d611971565b868352848452818320868452845281832054878452858552828420828552855280838520558352600784528183205538611999565b611a2687600052600460205260406000207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055565b848c52600381528d8c206000198154019055611783565b602488868951917f64a0ae92000000000000000000000000000000000000000000000000000000008352820152fd5b5082903461058f57611a7d366120aa565b91835193602085019085821067ffffffffffffffff831117611aa85761032b96975052858452612c81565b60248760418a634e487b7160e01b835252fd5b83823461058f578060031936011261058f576020906114d0611adb611f6d565b602435906128a4565b833461094b5761032b611af6366120aa565b91612600565b83823461058f578160031936011261058f576020906008549051908152f35b5082903461058f57606060031936011261058f57823590611b3a611f88565b60443567ffffffffffffffff8111610d5f57611b59903690870161203d565b611b67843361024d826134e2565b6001600160a01b03835192611b7b84611fb4565b1682526020820152611b8c81613663565b828452600b602052611ba0818386206125d6565b611ba983613898565b828452600b60205281842054906000198201918211611bfe579061053b83927fdedccb02f6c0249f96cf577d6a79d5b7869c1effa31e4416b730a0d71b68720a945193849384528060208501528301906121d6565b602485601188634e487b7160e01b835252fd5b5034610462578060031936011261046257611c2a611f6d565b91602435611c37816134e2565b33151580611d08575b80611ce0575b611cb15781906001600160a01b03809616958691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258880a484526020528220907fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905580f35b83517fa9fbf51f0000000000000000000000000000000000000000000000000000000081523381850152602490fd5b506001600160a01b0381168652600560205283862033875260205260ff848720541615611c46565b50336001600160a01b0382161415611c40565b5090346104625760206003193601126104625781602093826001600160a01b039335611d46816134e2565b50825285522054169051908152f35b50823461094b578060031936011261094b578151918182549260018460011c9160018616958615611e18575b60209687851081146112d2578899509688969785829a52918260001461128d575050600114611dbd575050506106c59291611222910385612002565b91908693508280527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b828410611e0057505050820101816112226106c561120f565b8054848a018601528895508794909301928101611de7565b92607f1692611d81565b8490843461046257602060031936011261046257357fffffffff00000000000000000000000000000000000000000000000000000000811680910361046257602092507f780e9d63000000000000000000000000000000000000000000000000000000008114908115611e97575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115611efb575b8115611ed1575b5083611e90565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483611eca565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150611ec3565b60005b838110611f385750506000910152565b8181015183820152602001611f28565b90601f19601f602093611f6681518092818752878088019101611f25565b0116010190565b600435906001600160a01b0382168203611f8357565b600080fd5b602435906001600160a01b0382168203611f8357565b604435906001600160a01b0382168203611f8357565b6040810190811067ffffffffffffffff821117611fd057604052565b634e487b7160e01b600052604160045260246000fd5b6080810190811067ffffffffffffffff821117611fd057604052565b90601f601f19910116810190811067ffffffffffffffff821117611fd057604052565b67ffffffffffffffff8111611fd05760051b60200190565b9080601f83011215611f8357602090823561205781612025565b936120656040519586612002565b81855260208086019260051b820101928311611f8357602001905b82821061208e575050505090565b813563ffffffff81168103611f83578152908301908301612080565b6003196060910112611f83576001600160a01b03906004358281168103611f8357916024359081168103611f83579060443590565b9190604083820312611f8357604051926120f884611fb4565b8367ffffffffffffffff8235818111611f83578461211791850161203d565b825260209283810135918211611f8357019280601f85011215611f8357833561213f81612025565b9461214d6040519687612002565b818652848087019260051b820101928311611f83578401905b828210612174575050500152565b81356fffffffffffffffffffffffffffffffff81168103611f83578152908401908401612166565b90815180825260208080930193019160005b8281106121bc575050505090565b835163ffffffff16855293810193928101926001016121ae565b90604060206121fc936001600160a01b038151168452015191816020820152019061219c565b90565b6003196040910112611f83576004359060243590565b90815180825260208080930193019160005b828110612235575050505090565b835185529381019392810192600101612227565b6003196060910112611f8357600435906024359060443590565b9190612278835160e0835260e08301906121d6565b906122b86122a660209384870151858501526040870151604085015260608701518482036060860152612215565b60808601518382036080850152612215565b9160a08501519282810360a084015281808551928381520194019160005b8281106122f8575050505060c06121fc939401519060c0818403910152612215565b835160030b865294810194928101926001016122d6565b67ffffffffffffffff8111611fd057601f01601f191660200190565b9291926123378261230f565b916123456040519384612002565b829481845281830111611f83578281602093846000960137010152565b612375815160408452604084019061219c565b602080920151928281830391015281808451928381520193019160005b8281106123a0575050505090565b83516fffffffffffffffffffffffffffffffff1685529381019392810192600101612392565b80548210156123e25760005260206000209060011b0190600090565b634e487b7160e01b600052603260045260246000fd5b906125c0576001600160a01b038251167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161781556001809101916020809101519182519267ffffffffffffffff8411611fd057680100000000000000008411611fd05782908554858755808610612556575b5001926000948552828520928160031c94865b86811061251657507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8831680840393036124be575b50505050505050565b929190865b8281106124dd5750505050500155388080808080806124b5565b9091928261250a869963ffffffff84985116908560021b60031b9163ffffffff809116831b921b19161790565b980194939291016124c3565b849088895b85600882106125305750508188015501612480565b8551950194889463ffffffff918216600584901b90811b92901b1990931617910161251b565b90915060008660005284600020600780880160031c8201930160031c0191601c8760021b16806125a6575b509084869493925b8381106125985750505061246d565b828155879550869101612589565b6000199081830191825491890360031b1c16905538612581565b634e487b7160e01b600052600060045260246000fd5b9081549168010000000000000000831015611fd057826105179160016125fe950181556123c6565b565b916001600160a01b0380831693841561287357600094838652602095600287526040968488832054169633612863575b87158015612813575b848452600383528984206001815401905587845260028352898420857fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905587858a7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8780a4156127975760085487845260098352808a8520556801000000000000000081101561278357876118268260016126dc940160085561291e565b838803612731575b5050505016928383036126f75750505050565b6064945051927f64283d7b000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b61273a90612b5e565b92600019840193841161276f5782916007918a94526006815283832085845281528784842055878352522055388080806126e4565b602483634e487b7160e01b81526011600452fd5b602484634e487b7160e01b81526041600452fd5b8784146126dc576127a788612b5e565b87845260078352898420548181036127dc575b50878452838a81205588845260068352898420908452825282898120556126dc565b898552600684528a852082865284528a8520548a8652600685528b86208287528552808c8720558552600784528a852055386127ba565b61284c88600052600460205260406000207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055565b888452600383528984206000198154019055612639565b61286e87338a6139ac565b612630565b60246040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260006004820152fd5b6128ad81612b5e565b8210156128da576001600160a01b0316600052600660205260406000209060005260205260406000205490565b6040517fa57d13dc0000000000000000000000000000000000000000000000000000000081526001600160a01b039190911660048201526024810191909152604490fd5b6008548110156123e25760086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30190600090565b9190826040910312611f83576020825192015190565b6121fc93926001600160a01b0360609316825260208201528160408201520190612362565b90604080519261299f84611fb4565b836001600160a01b03825416815260018092019260405193848186925495868352602096878094019260005283600020956000905b826007830110612aed5750612a3096549285838310612ad7575b838310612abf575b838310612aa6575b838310612a8d575b838310612a74575b838310612a5b575b838310612a42575b505010612a34575b5090500384612002565b0152565b60e01c815201849038612a26565b90919463ffffffff8560c01c1681520193013885612a1e565b81929563ffffffff8660a01c1681520194019085612a16565b81929563ffffffff8660801c1681520194019085612a0e565b81929563ffffffff8660601c1681520194019085612a06565b81929563ffffffff8660401c16815201940190856129fe565b81929563ffffffff86831c16815201940190856129f6565b81929563ffffffff8616815201940190856129ee565b875463ffffffff8082168752818c1c81168c88015281831c811687840152606082811c821690880152608082811c82169088015260a082811c82169088015260c082811c9091169087015260e090811c90860152968301968a965089955061010090940193600891909101906129d4565b6001600160a01b03168015612b7e57600052600360205260406000205490565b60246040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152fd5b60405190612bbc82611fb4565b6060602083600081520152565b90612bd382612025565b612be06040519182612002565b828152601f19612bf08294612025565b0190602036910137565b80518210156123e25760209160051b010190565b6040519060e0820182811067ffffffffffffffff821117611fd057604052606060c083612c39612baf565b8152600060208201526000604082015282808201528260808201528260a08201520152565b91908201809211612c6b57565b634e487b7160e01b600052601160045260246000fd5b9190612c8e828285612600565b803b612c9b575b50505050565b612cf76001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190611f48565b03906020816000938185885af190829082612dbf575b5050612d5d5782612d1c613aa7565b8051919082612d5657602482604051907f64a0ae920000000000000000000000000000000000000000000000000000000082526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612d8e575038808080612c95565b602490604051907f64a0ae920000000000000000000000000000000000000000000000000000000082526004820152fd5b909192506020813d602011612e18575b81612ddc60209383612002565b8101031261058f5751907fffffffff000000000000000000000000000000000000000000000000000000008216820361094b5750903880612d0d565b3d9150612dcf565b906020612e44610752612e31612c0e565b9385600052600b845260406000206123c6565b8083526001600160a01b03815116608052015192600080612e658651612bc9565b90612e708751612bc9565b91875195601f19612e99612e8389612025565b98612e916040519a8b612002565b808a52612025565b01366020890137612eaa8951612bc9565b976000965b8a518810156133b75763ffffffff612ec7898d612bfa565b51169a604051937f22cd85a80000000000000000000000000000000000000000000000000000000085528c600486015260c0856024816080515afa94851561306957612f7195602091600091613398575b509d604051809781927ff98175c400000000000000000000000000000000000000000000000000000000835288306004850191604091949363ffffffff916001600160a01b036060860197168552602085015216910152565b03816080515afa8015613069578d95600091613341575b506fffffffffffffffffffffffffffffffff169c505b63ffffffff60a086015116156130ac5760049c6fffffffffffffffffffffffffffffffff60408701511690811560001461307557505063ffffffff60a060005b960151166040519d8e7f22cd85a8000000000000000000000000000000000000000000000000000000008152015260c08d6024816080515afa9c8d156130695760a09d63ffffffff9160009161303a575b50959d50612f9e9050565b61305c915060c03d60c011613062575b6130548183612002565b810190613d9c565b3861302f565b503d61304a565b6040513d6000823e3d90fd5b6130a760a09163ffffffff936fffffffffffffffffffffffffffffffff8a511690600190818111908218021891613d19565b612fde565b929a9b98979590939198608083015192604051917f3256cfa90000000000000000000000000000000000000000000000000000000083528460030b600484015260e0836024816080515afa92831561306957600093613316575b508161091f916fffffffffffffffffffffffffffffffff602081604061313b97015116930151169080831083821802186144c6565b926fffffffffffffffffffffffffffffffff604083015116938085108582180218936fffffffffffffffffffffffffffffffff6020818551169401511690600095600094826132f0575b505050506040517fd0c93a7c0000000000000000000000000000000000000000000000000000000081526020816004816080515afa918215613069578f8e938d9360009161327d575b5094613270969461323b85856fffffffffffffffffffffffffffffffff9795613231899761322b60019f9a9d61321f6132659f61320e9060030b83613fd2565b9160018860030b0160030b90613fd2565b908a8c168c8e16614359565b92612bfa565b5260030b92612bfa565b52166132478d8d612bfa565b52166132538b89612bfa565b5261325e8a88612bfa565b5190612c5e565b9561325e8989612bfa565b9601969998909199612eaf565b95969450505090506020833d6020116132e8575b8161329e60209383612002565b81010312611f83576001948f613270958f61323b8f6fffffffffffffffffffffffffffffffff9687956132318361322b6132659d51989d505050509550959a5095505094966131ce565b3d9150613291565b8293975061330c949550918161330692936145ac565b956145ac565b9038808080613185565b61091f9193509161333861313b9360e03d60e011610cca57610cbb8183612002565b93915091613106565b9550506020853d602011613390575b8161335d60209383612002565b81010312611f835763ffffffff60a06fffffffffffffffffffffffffffffffff8f9761338890613536565b925050612f88565b3d9150613350565b6133b1915060c03d60c011613062576130548183612002565b38612f18565b989650509750929490604051907f3ab72c100000000000000000000000000000000000000000000000000000000082526020826004816080515afa918215613069576000926134ae575b50604051907f21272d4c0000000000000000000000000000000000000000000000000000000082526020826004816080515afa91821561306957600092613478575b506134579261345191613e29565b96613e29565b9360c088015260a08701526080860152606085015260408401526020830152565b9091506020813d6020116134a6575b8161349460209383612002565b81010312611f83575190613457613443565b3d9150613487565b9091506020813d6020116134da575b816134ca60209383612002565b81010312611f8357519038613401565b3d91506134bd565b8060005260026020526001600160a01b0360406000205416908115613505575090565b602490604051907f7e2732890000000000000000000000000000000000000000000000000000000082526004820152fd5b51906fffffffffffffffffffffffffffffffff82168203611f8357565b51908160070b8203611f8357565b51908160030b8203611f8357565b51908115158203611f8357565b519063ffffffff82168203611f8357565b519060ff82168203611f8357565b80916101209283910312611f835760405191820182811067ffffffffffffffff821117611fd0576040526135ce81613536565b82526135dc60208201613536565b60208301526135ed60408201613553565b60408301526135fe60608201613553565b6060830152608081015164ffffffffff81168103611f8357608083015261362760a08201613561565b60a083015261363860c0820161356f565b60c083015261364960e0820161357c565b60e083015261365c61010080920161358d565b9082015290565b6001600160a01b038082511691604092835180917f1865c57d0000000000000000000000000000000000000000000000000000000082528160046101209485935afa91821561388d579160e09163ffffffff93600092613870575b50500151169282825116928151937f578eaca400000000000000000000000000000000000000000000000000000000855260048501526020938481602481857f0000000000000000000000000000000000000000000000000000000000000000165afa90811561386557600091613830575b501561380757836004918451168351928380927f99013aa80000000000000000000000000000000000000000000000000000000082525afa9081156137fc576000916137c7575b5061379e5750015190620186a0811015613794576125fe91613f25565b506125fe90613e4f565b600490517fdadac8e4000000000000000000000000000000000000000000000000000000008152fd5b90508381813d83116137f5575b6137de8183612002565b81010312611f83576137ef9061356f565b38613777565b503d6137d4565b82513d6000823e3d90fd5b600482517fdd4927b2000000000000000000000000000000000000000000000000000000008152fd5b90508481813d831161385e575b6138478183612002565b81010312611f83576138589061356f565b38613730565b503d61383d565b83513d6000823e3d90fd5b6138869250803d10610cf757610ce88183612002565b38806136be565b85513d6000823e3d90fd5b600090808252600b602092600b60205260409060408120549260019560018511156124b5576138c685612025565b956138d46040519788612002565b858752601f196138e387612025565b01366020890137835b8681106138fe57505050505050505050565b8890828652848452613912818888206123c6565b506001600160a01b0380915416613929838c612bfa565b52865b82811061393b575050016138ec565b9082935061394a81938c612bfa565b511682613957838d612bfa565b511614613969578a01908a929161392c565b6044838984613978838f612bfa565b51169051917f0fdffd6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6001600160a01b03908183168015159081613a48575b50156139ce5750505050565b16613a0457602482604051907f7e2732890000000000000000000000000000000000000000000000000000000082526004820152fd5b6040517f177e802f0000000000000000000000000000000000000000000000000000000081526001600160a01b039190911660048201526024810191909152604490fd5b82841680821492508215613a80575b508115613a66575b50386139c2565b905084600052600460205282604060002054161438613a5f565b909150600052600560205260406000208160005260205260ff604060002054169038613a57565b3d15613ad2573d90613ab88261230f565b91613ac66040519384612002565b82523d6000602084013e565b606090565b60e081830312611f835760405191613aee83611fe6565b613af782613536565b8352602090613b0860208401613536565b6020850152613b1960408401613536565b604085015280607f84011215611f835760405192613b3684611fe6565b839060e08101928311611f8357606001905b828210613b5b5750505050606082015290565b838091613b678461357c565b815201910190613b48565b6fffffffffffffffffffffffffffffffff90818111613b8f571690565b604490604051907f6dfcc650000000000000000000000000000000000000000000000000000000008252608060048301526024820152fd5b90613c065750805115613bdc57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580613c51575b613c17575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b15613c0f565b8115613c64570490565b634e487b7160e01b600052601260045260246000fd5b908082029060001981840990828083109203918083039214613d0857670de0b6b3a76400009082821115613cde577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b60046040517f227bc153000000000000000000000000000000000000000000000000000000008152fd5b5050670de0b6b3a764000091500490565b90918282029160001984820993838086109503948086039514613d8f5784831115613cde5782910981600003821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b5050906121fc9250613c5a565b908160c0910312611f83576040519060c0820182811067ffffffffffffffff821117611fd057613e219160a091604052613dd581613536565b8452613de360208201613536565b6020850152613df460408201613536565b6040850152613e056060820161358d565b6060850152613e1660808201613561565b60808501520161357c565b60a082015290565b90600181148015613e47575b15613e3e575090565b6121fc91613c5a565b508115613e35565b8051906001916001811115613f205760009392916000198201828111845b613e7b575b50505050509050565b80612c6b5781871015613f1b57848701808811612c6b575b848110613ea557509584019584613e6d565b63ffffffff80613eb58a87612bfa565b511681613ec28488612bfa565b511614613ed157508501613e93565b613edb8286612bfa565b516040517f79926e7800000000000000000000000000000000000000000000000000000000815260048101939093521663ffffffff166024820152604490fd5b613e72565b505050565b8051906001926001831115612c955760089060081c60018101809111612c6b57613f4e90612bc9565b9160005b848110613f6157505050505050565b613f6b8183612bfa565b5162ffffff9060ff90613f87838a8484161b92881c1688612bfa565b5116613fc25790613fbb888493613f9f829688612bfa565b519384891c1693161b613fb28389612bfa565b51179187612bfa565b5201613f52565b8263ffffffff613edb8287612bfa565b908060030b90600082126000146143545760000360030b5b63ffffffff80809416911602918216828103612c6b576204eb4a106143235760018216156142fa5770ffffffffffffffffffffffffffffffffff6ffffcb933bd6fad9d3af5f0b9f25db4d65b1690600283166142de575b600483166142c2575b600883166142a6575b6010831661428a575b6020831661426e575b60408316614252575b608092838116614237575b610100811661421c575b6102008116614201575b61040081166141e6575b61080081166141cb575b61100081166141b0575b6120008116614195575b614000811661417a575b618000811661415f575b620100008116614144575b620200008116614129575b620400001661410f575b600012614100575b670de0b6b3a764000002901c90565b8015613c6457600019046140f1565b6d2216e584f630389b2052b8db590e909102821c906140e9565b6e5d6af8dedbcb3a6ccb7ce618d14225909202831c916140df565b916f09aa508b5b7e5a9780b0cc4e25d61a5602831c916140d4565b916f31be135f97da6e09a19dc367e3b6da4002831c916140c9565b916f70d869a156ddd32a39e257bc3f50aa9b02831c916140bf565b916fa9f746462d8f7dd10e744d913d03333302831c916140b5565b916fd097f3bdfd254ee83bdd3f248e7e785e02831c916140ab565b916fe7159475a2c578ef4f1d17b2b235d48002831c916140a1565b916ff3392b0822b88206f8abe8a3b44dd9be02831c91614097565b916ff987a7253ac4d9194200696907cf2e3702831c9161408d565b916ffcbe86c7900aecf64236ab31f1f9dcb502831c91614083565b916ffe5dee046a99d51e2cc356c2f617dbe002831c91614079565b906fff2ea16466c9838804e327cb417cafcb0260801c9061406e565b906fff973b41fa98cd2e57b660be99eb2c4a0260801c90614065565b906fffcb9843d60f67b19e8887e0bd251eb70260801c9061405c565b906fffe5caca7e10e81259b3cddc7a0649410260801c90614053565b906ffff2e50f5f656ac9229c67059486f3890260801c9061404a565b906ffff97272373d41fd789c8cb37ffcaa1c0260801c90614041565b70ffffffffffffffffffffffffffffffffff700100000000000000000000000000000000614036565b602490604051907f20ab18100000000000000000000000000000000000000000000000000000000082526004820152fd5b613fea565b9091928381039160009481604e1c1580614405575b6143f4575b84156143e75781156143d4576143c86143cf956143c285876143bd633b9aca00966143a86143a1858b61447a565b91876144a8565b0160011c976143b78980613c7a565b95613c7a565b613d19565b016144e0565b0201613d19565b901c90565b6143e291506143cf946144a8565b6144c6565b5090506143cf925061447a565b6039955093851b9390851b90614373565b5084604e1c1561436e565b91929390821561447257908185921561446a5761443f614446936144559561443888866144a8565b019361447a565b019061447a565b670de0b6b3a7640000026144e0565b90818111908218021890818110908218021890565b505050505090565b505050905090565b670de0b6b3a76400009081810291831561449f575b8183041490151715611f83570490565b6001935061448f565b818102918183041490151715611f8357670de0b6b3a7640000900490565b81810291831561449f578183041490151715611f83570490565b60b58171010000000000000000000000000000000000811015614595575b80690100000000000000000062010000921015614588575b6501000000000081101561457b575b630100000081101561456e575b010260121c60019080830401811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c8080920410900390565b60101c9160081b91614532565b60201c9160101b91614525565b60401c9160201b91614516565b5068b500000000000000009050608082901c6144fe565b916145e09161091f916fffffffffffffffffffffffffffffffff808092166001811190600118026001189216908516613d19565b81811090821802189056fea2646970667358221220e9fd2457b65203d30ad0388375cd2311f20e2f760422a0cd9b3bfd04dcd0829064736f6c63430008190033000000000000000000000000dbed345273897d2cea8ad530c4c64a922ef98deb0000000000000000000000000a7e848aca42d879ef06507fca0e7b33a0a63c1e

Deployed Bytecode

0x60a060408181526004908136101561001657600080fd5b600092833560e01c90816301ffc9a714611e225750806306fdde0314611d55578063081812fc14611d1b578063095ea7b314611c1157806310c01fcd14611b1b57806318160ddd14611afc57806323b872dd14611ae45780632f745c5914611abb57806342842e0e14611a6c57806345d77f7e1461170a57806348fd65fe146116df5780634f6ccce7146116715780636352211e146116415780636621a76f146115a95780636f78d298146114d757806370a08231146114aa578063751df17a1461146757806375794a3c1461144857806378acef13146114205780637af50dff146113355780637fc3d351146112ef57806395d89b41146111b75780639e59e5981461114d578063a22cb4651461107a578063a58b083314610f4d578063a699094614610efe578063ac9650d814610d63578063b88d4fde14610cfe578063b9e4530014610ac7578063c45a015514610a83578063c87b56dd1461094e578063cc63c52f1461070d578063cd04b9cd146106c9578063d2d8a77014610695578063e05a807b14610593578063e985e9c514610541578063f66d8d4d146104665763f912f1da146101c657600080fd5b34610462578060031936011261046257813590602492833567ffffffffffffffff9182821161045e573660238301121561045e57818101359161020883612025565b9261021586519485612002565b808452602094888686019260051b8401019236841161045a57898101925b8484106103cc575050505050610252853361024d826134e2565b6139ac565b848752600b95600b84528488208054918982558261032e575b50505050837f7eec32dd7050b28720bc3a144a9b54740b810701816e7583f829ecf6dd6a83b48780a2855b815181101561032157806102b56102af60019385612bfa565b51613663565b8588528684526102d28589206102cb8386612bfa565b51906125d6565b857fdedccb02f6c0249f96cf577d6a79d5b7869c1effa31e4416b730a0d71b68720a6103186103018487612bfa565b5188519182918683528a8a8401528a8301906121d6565b0390a201610296565b8661032b86613898565b80f35b6001937f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841684036103bb57505088528388209060011b8101905b818110610376578061026b565b8881558281018054908a815581610392575b5050600201610369565b8a52836007878c20920160031c8201915b8281106103b05750610388565b8b81550184906103a3565b60118b91634e487b7160e01b835252fd5b8335838111610456578201897fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc82360301126104565789519161040e83611fb4565b8c8201356001600160a01b0381168103610452578352604482013592858411610452576104438b94938f86953692010161203d565b83820152815201930192610233565b8e80fd5b8c80fd5b8a80fd5b8680fd5b8280fd5b50903461046257608060031936011261046257803591602435610487611f9e565b926064359367ffffffffffffffff851161045e576104cc61053b927fdedccb02f6c0249f96cf577d6a79d5b7869c1effa31e4416b730a0d71b68720a9636910161203d565b6104da873361024d826134e2565b6001600160a01b038551926104ee84611fb4565b16825260208201526104ff81613663565b858752600b60205261051d8161051785878b206123c6565b906123f8565b61052686613898565b835193849384528060208501528301906121d6565b0390a280f35b83823461058f578060031936011261058f5760ff81602093610561611f6d565b610569611f88565b6001600160a01b0391821683526005875283832091168252855220549151911615158152f35b5080fd5b50906060600319360112610462576105a9611f6d565b916024936024359267ffffffffffffffff93848111610462576105cf903690830161203d565b93604480359063ffffffff8083168093036106915796976001600160a01b031696855b895181101561068d5781610606828c612bfa565b5116893b1561068957878c918589838e8a8f5197889687957f8e5430a70000000000000000000000000000000000000000000000000000000087528601528401525af1801561067f5761065d575b506001016105f2565b85811161066d5788526001610654565b8b88604189634e487b7160e01b835252fd5b89513d8a823e3d90fd5b8780fd5b8680f35b8580fd5b83823461058f576106c5906106b26106ac366121ff565b90612e20565b9051918291602083526020830190612263565b0390f35b83823461058f578160031936011261058f57602090516001600160a01b037f000000000000000000000000dbed345273897d2cea8ad530c4c64a922ef98deb168152f35b50913461094b57829061071f36612249565b84959195519261072e84611fb4565b606084526020936107586107528683019960608b52848952600b88528989206123c6565b50612990565b906001600160a01b038683015192838352511693601f19610791845161078961078082612025565b9c519c8d612002565b808c52612025565b0136888b0137875b83518110156108b05761080e888d63ffffffff6107b68589612bfa565b51169051809381927ff98175c40000000000000000000000000000000000000000000000000000000083528a8d3090850191604091949363ffffffff916001600160a01b036060860197168552602085015216910152565b03818a5afa9081156108a657908b92918b9161084d575b506fffffffffffffffffffffffffffffffff61084383600195612bfa565b9116905201610799565b809293508a8092503d831161089f575b6108678183612002565b8101031261089b57908a6fffffffffffffffffffffffffffffffff61084383610891600196613536565b9395505050610825565b8980fd5b503d61085d565b8d513d8c823e3d90fd5b508a87918b8a8c8252670de0b6b3a764000083106108df575b5050506106c59051928284938452830190612362565b94909291945b8351805182101561093a57908061092461091f896001956109186fffffffffffffffffffffffffffffffff958692612bfa565b5116613c7a565b613b72565b90610930838851612bfa565b91169052016108e5565b505093506106c591509084806108c9565b80fd5b50346104625760209182600319360112610a7f578381356044610970826134e2565b936001600160a01b0380875196879586947f1853083b0000000000000000000000000000000000000000000000000000000086528501521660248301527f000000000000000000000000dbed345273897d2cea8ad530c4c64a922ef98deb165afa938415610a745780946109f4575b50506106c59051928284938452830190611f48565b909193503d8082843e610a078184612002565b820191838184031261058f5780519067ffffffffffffffff8211610462570182601f8201121561058f57805191610a3d8361230f565b93610a4a87519586612002565b83855285848401011161094b57508291610a6c9185806106c596019101611f25565b9290386109df565b8251903d90823e3d90fd5b8380fd5b83823461058f578160031936011261058f57602090516001600160a01b037f0000000000000000000000000a7e848aca42d879ef06507fca0e7b33a0a63c1e168152f35b50606060031936011261046257610adc611f6d565b90602435906001600160a01b03604435931681517f1865c57d0000000000000000000000000000000000000000000000000000000081526101209081818881865afa918215610c93579060a092918992610cd1575b5050015160030b8251917f3256cfa9000000000000000000000000000000000000000000000000000000008352818784015260e083602481845afa928315610c935790879392918993610c9d575b506020908551948580927fd0c93a7c0000000000000000000000000000000000000000000000000000000082525afa928315610c93578893610c5d575b50610bdb836001610bd084610c0997613fd2565b930160030b90613fd2565b906fffffffffffffffffffffffffffffffff60208185511694015116610c0383838387614359565b93614410565b908282108015610c54575b610c1c578580f35b6064955051937ffcb505c700000000000000000000000000000000000000000000000000000000855284015260248301526044820152fd5b50838211610c14565b92506020833d602011610c8b575b81610c7860209383612002565b8101031261068957915191610bdb610bbc565b3d9150610c6b565b84513d8a823e3d90fd5b6020919350610cc39060e03d60e011610cca575b610cbb8183612002565b810190613ad7565b9290610b7f565b503d610cb1565b610cf09250803d10610cf7575b610ce88183612002565b81019061359b565b3880610b31565b503d610cde565b50503461058f57608060031936011261058f57610d19611f6d565b610d21611f88565b9060643567ffffffffffffffff8111610d5f5736602382011215610d5f5761032b93816024610d559336930135910161232b565b9160443591612c81565b8480fd5b5091903461058f576020918260031936011261094b5781359167ffffffffffffffff90818411610462573660238501121561046257830135908082116104625760246005923660248260051b88010111610d5f5792610dc184612025565b95610dce89519788612002565b848752601f19610ddd86612025565b0188875b828110610eee5750505085917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd82360301925b868110610e78578a8a8a8a83519280840190808552835180925280868601968360051b870101940192955b828710610e4c5785850386f35b909192938280610e6883603f198a600196030186528851611f48565b9601920196019592919092610e3f565b8481831b8401013584811215610eea578301858101359087821161089b5760440190803603821361089b5789808d610eb860019695610ece95369161232b565b80519101305af4610ec7613aa7565b9030613bc7565b610ed8828c612bfa565b52610ee3818b612bfa565b5001610e14565b8880fd5b60608a82018301528a9101610de1565b50602060031936011261046257813590814211610f19578380f35b6044935051917f3442e977000000000000000000000000000000000000000000000000000000008352820152426024820152fd5b5091903461058f57610f5e36612249565b9391808394929452602094600b865286842054908181109082180218918483039283116110675750610f8f82612025565b93610f9c87519586612002565b828552601f19610fab84612025565b0186855b82811061105157505050835b83811061101f575050505083519280840190808552835180925280868601968360051b870101940192955b828710610ff35785850386f35b90919293828061100f83603f198a600196030186528851612263565b9601920196019592919092610fe6565b8061104a61102f84600194612c5e565b6110398187612e20565b611043828b612bfa565b5288612bfa565b5001610fbb565b611059612c0e565b82828a010152018790610faf565b836011602492634e487b7160e01b835252fd5b5034610462578060031936011261046257611093611f6d565b9060243591821515809303610d5f576001600160a01b031692831561111f575033845260056020528084208385526020528084207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff8416179055519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b8360249251917f5b08ba18000000000000000000000000000000000000000000000000000000008352820152fd5b50823461094b57602060031936011261094b57611168611f6d565b9161117283612b5e565b61117b81612bc9565b925b818110611199578251602080825281906106c590820187612215565b806111a6600192876128a4565b6111b08287612bfa565b520161117d565b50823461094b578060031936011261094b5781519181600192600154938460011c91600186169586156112e5575b60209687851081146112d2578899509688969785829a52918260001461128d575050600114611231575b5050506106c59291611222910385612002565b51928284938452830190611f48565b9190869350600183527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b82841061127557505050820101816112226106c561120f565b8054848a01860152889550879490930192810161125c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168782015293151560051b8601909301935084925061122291506106c5905061120f565b60248360228c634e487b7160e01b835252fd5b92607f16926111e5565b83823461058f576113226107526106c5938361130a366121ff565b9290611314612baf565b508152600b602052206123c6565b90519182916020835260208301906121d6565b5091903461058f57606060031936011261058f578035611353611f88565b9060443567ffffffffffffffff8111610d5f57916113c79391856001600160a01b036113838996369087016120df565b94611392843361024d826134e2565b8651978896879586937ff957f1ca0000000000000000000000000000000000000000000000000000000085523390850161296b565b0393165af19081156114165782916113e7575b5082519182526020820152f35b90506114099150823d841161140f575b6114018183612002565b810190612955565b386113da565b503d6113f7565b83513d84823e3d90fd5b509034610462576020600319360112610462576020928291358152600b845220549051908152f35b83823461058f578160031936011261058f57602090600a549051908152f35b83823461058f578060031936011261058f576020906001600160a01b0361148c611f6d565b916114a360243561149c816134e2565b94856139ac565b5191168152f35b83823461058f57602060031936011261058f576020906114d06114cb611f6d565b612b5e565b9051908152f35b5091903461058f576020908160031936011261046257919091358152600b825282812090815461150681612025565b9061151386519283612002565b8082528482018094845285842084915b83831061158457505050508451938085019181865251809252858501958260051b8601019392955b8287106115585785850386f35b90919293828061157483603f198a6001960301865288516121d6565b960192019601959291909261154b565b600288600192611597859b98999b612990565b81520192019201919096949396611523565b5091903461058f57608060031936011261058f5780356115c7611f88565b6115cf611f9e565b9060643567ffffffffffffffff81116106915790856001600160a01b036115fc89969594369089016120df565b9661160b863361024d826134e2565b6113c78751988997889687947ff957f1ca000000000000000000000000000000000000000000000000000000008652850161296b565b50823461094b57602060031936011261094b57506001600160a01b03611669602093356134e2565b915191168152f35b509034610462576020600319360112610462578035926008548410156116ab5760208361169d8661291e565b91905490519160031b1c8152f35b604493919251927fa57d13dc0000000000000000000000000000000000000000000000000000000084528301526024820152fd5b83823461058f578060031936011261058f576020906116ff6114cb611f6d565b602435109051908152f35b503461046257606060031936011261046257611724611f6d565b9261172d611f88565b9060443567ffffffffffffffff811161058f5761174d903690860161203d565b600a54956001600160a01b03908181168015611a3d578885526020988992600284528489882054168381156002811597886119ed575b838c52600381528d8c2060018154019055868c52528b8a20827fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790558482847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8d80a415611966575060085483895260098d52808b8a205568010000000000000000811015611953579061183e8461182684600189960160085561291e565b90919060001983549160031b92831b921b1916179055565b03611905575b5050506118d657600a549560001987146110675750918593917fdedccb02f6c0249f96cf577d6a79d5b7869c1effa31e4416b730a0d71b68720a9360018601600a5586519361189285611fb4565b168352878301526118a282613663565b838152600b87526118b5828683206125d6565b6118cd855192839283528689840152868301906121d6565b0390a251908152f35b602486848751917f73c6ac6e000000000000000000000000000000000000000000000000000000008352820152fd5b61190e90612b5e565b91600019830192831161194057865260068a528786208287528a52808887205585526007895286852055388080611844565b60248760118c634e487b7160e01b835252fd5b60248960418e634e487b7160e01b835252fd5b908a8d838303611978575b505061183e565b6006908b61198585612b5e565b9388825260078352808220548581036119b8575b50888252812055838c52528b8a20908a528d52888b8120558a8d611971565b868352848452818320868452845281832054878452858552828420828552855280838520558352600784528183205538611999565b611a2687600052600460205260406000207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055565b848c52600381528d8c206000198154019055611783565b602488868951917f64a0ae92000000000000000000000000000000000000000000000000000000008352820152fd5b5082903461058f57611a7d366120aa565b91835193602085019085821067ffffffffffffffff831117611aa85761032b96975052858452612c81565b60248760418a634e487b7160e01b835252fd5b83823461058f578060031936011261058f576020906114d0611adb611f6d565b602435906128a4565b833461094b5761032b611af6366120aa565b91612600565b83823461058f578160031936011261058f576020906008549051908152f35b5082903461058f57606060031936011261058f57823590611b3a611f88565b60443567ffffffffffffffff8111610d5f57611b59903690870161203d565b611b67843361024d826134e2565b6001600160a01b03835192611b7b84611fb4565b1682526020820152611b8c81613663565b828452600b602052611ba0818386206125d6565b611ba983613898565b828452600b60205281842054906000198201918211611bfe579061053b83927fdedccb02f6c0249f96cf577d6a79d5b7869c1effa31e4416b730a0d71b68720a945193849384528060208501528301906121d6565b602485601188634e487b7160e01b835252fd5b5034610462578060031936011261046257611c2a611f6d565b91602435611c37816134e2565b33151580611d08575b80611ce0575b611cb15781906001600160a01b03809616958691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258880a484526020528220907fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905580f35b83517fa9fbf51f0000000000000000000000000000000000000000000000000000000081523381850152602490fd5b506001600160a01b0381168652600560205283862033875260205260ff848720541615611c46565b50336001600160a01b0382161415611c40565b5090346104625760206003193601126104625781602093826001600160a01b039335611d46816134e2565b50825285522054169051908152f35b50823461094b578060031936011261094b578151918182549260018460011c9160018616958615611e18575b60209687851081146112d2578899509688969785829a52918260001461128d575050600114611dbd575050506106c59291611222910385612002565b91908693508280527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b828410611e0057505050820101816112226106c561120f565b8054848a018601528895508794909301928101611de7565b92607f1692611d81565b8490843461046257602060031936011261046257357fffffffff00000000000000000000000000000000000000000000000000000000811680910361046257602092507f780e9d63000000000000000000000000000000000000000000000000000000008114908115611e97575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115611efb575b8115611ed1575b5083611e90565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483611eca565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150611ec3565b60005b838110611f385750506000910152565b8181015183820152602001611f28565b90601f19601f602093611f6681518092818752878088019101611f25565b0116010190565b600435906001600160a01b0382168203611f8357565b600080fd5b602435906001600160a01b0382168203611f8357565b604435906001600160a01b0382168203611f8357565b6040810190811067ffffffffffffffff821117611fd057604052565b634e487b7160e01b600052604160045260246000fd5b6080810190811067ffffffffffffffff821117611fd057604052565b90601f601f19910116810190811067ffffffffffffffff821117611fd057604052565b67ffffffffffffffff8111611fd05760051b60200190565b9080601f83011215611f8357602090823561205781612025565b936120656040519586612002565b81855260208086019260051b820101928311611f8357602001905b82821061208e575050505090565b813563ffffffff81168103611f83578152908301908301612080565b6003196060910112611f83576001600160a01b03906004358281168103611f8357916024359081168103611f83579060443590565b9190604083820312611f8357604051926120f884611fb4565b8367ffffffffffffffff8235818111611f83578461211791850161203d565b825260209283810135918211611f8357019280601f85011215611f8357833561213f81612025565b9461214d6040519687612002565b818652848087019260051b820101928311611f83578401905b828210612174575050500152565b81356fffffffffffffffffffffffffffffffff81168103611f83578152908401908401612166565b90815180825260208080930193019160005b8281106121bc575050505090565b835163ffffffff16855293810193928101926001016121ae565b90604060206121fc936001600160a01b038151168452015191816020820152019061219c565b90565b6003196040910112611f83576004359060243590565b90815180825260208080930193019160005b828110612235575050505090565b835185529381019392810192600101612227565b6003196060910112611f8357600435906024359060443590565b9190612278835160e0835260e08301906121d6565b906122b86122a660209384870151858501526040870151604085015260608701518482036060860152612215565b60808601518382036080850152612215565b9160a08501519282810360a084015281808551928381520194019160005b8281106122f8575050505060c06121fc939401519060c0818403910152612215565b835160030b865294810194928101926001016122d6565b67ffffffffffffffff8111611fd057601f01601f191660200190565b9291926123378261230f565b916123456040519384612002565b829481845281830111611f83578281602093846000960137010152565b612375815160408452604084019061219c565b602080920151928281830391015281808451928381520193019160005b8281106123a0575050505090565b83516fffffffffffffffffffffffffffffffff1685529381019392810192600101612392565b80548210156123e25760005260206000209060011b0190600090565b634e487b7160e01b600052603260045260246000fd5b906125c0576001600160a01b038251167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161781556001809101916020809101519182519267ffffffffffffffff8411611fd057680100000000000000008411611fd05782908554858755808610612556575b5001926000948552828520928160031c94865b86811061251657507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8831680840393036124be575b50505050505050565b929190865b8281106124dd5750505050500155388080808080806124b5565b9091928261250a869963ffffffff84985116908560021b60031b9163ffffffff809116831b921b19161790565b980194939291016124c3565b849088895b85600882106125305750508188015501612480565b8551950194889463ffffffff918216600584901b90811b92901b1990931617910161251b565b90915060008660005284600020600780880160031c8201930160031c0191601c8760021b16806125a6575b509084869493925b8381106125985750505061246d565b828155879550869101612589565b6000199081830191825491890360031b1c16905538612581565b634e487b7160e01b600052600060045260246000fd5b9081549168010000000000000000831015611fd057826105179160016125fe950181556123c6565b565b916001600160a01b0380831693841561287357600094838652602095600287526040968488832054169633612863575b87158015612813575b848452600383528984206001815401905587845260028352898420857fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905587858a7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8780a4156127975760085487845260098352808a8520556801000000000000000081101561278357876118268260016126dc940160085561291e565b838803612731575b5050505016928383036126f75750505050565b6064945051927f64283d7b000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b61273a90612b5e565b92600019840193841161276f5782916007918a94526006815283832085845281528784842055878352522055388080806126e4565b602483634e487b7160e01b81526011600452fd5b602484634e487b7160e01b81526041600452fd5b8784146126dc576127a788612b5e565b87845260078352898420548181036127dc575b50878452838a81205588845260068352898420908452825282898120556126dc565b898552600684528a852082865284528a8520548a8652600685528b86208287528552808c8720558552600784528a852055386127ba565b61284c88600052600460205260406000207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055565b888452600383528984206000198154019055612639565b61286e87338a6139ac565b612630565b60246040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260006004820152fd5b6128ad81612b5e565b8210156128da576001600160a01b0316600052600660205260406000209060005260205260406000205490565b6040517fa57d13dc0000000000000000000000000000000000000000000000000000000081526001600160a01b039190911660048201526024810191909152604490fd5b6008548110156123e25760086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30190600090565b9190826040910312611f83576020825192015190565b6121fc93926001600160a01b0360609316825260208201528160408201520190612362565b90604080519261299f84611fb4565b836001600160a01b03825416815260018092019260405193848186925495868352602096878094019260005283600020956000905b826007830110612aed5750612a3096549285838310612ad7575b838310612abf575b838310612aa6575b838310612a8d575b838310612a74575b838310612a5b575b838310612a42575b505010612a34575b5090500384612002565b0152565b60e01c815201849038612a26565b90919463ffffffff8560c01c1681520193013885612a1e565b81929563ffffffff8660a01c1681520194019085612a16565b81929563ffffffff8660801c1681520194019085612a0e565b81929563ffffffff8660601c1681520194019085612a06565b81929563ffffffff8660401c16815201940190856129fe565b81929563ffffffff86831c16815201940190856129f6565b81929563ffffffff8616815201940190856129ee565b875463ffffffff8082168752818c1c81168c88015281831c811687840152606082811c821690880152608082811c82169088015260a082811c82169088015260c082811c9091169087015260e090811c90860152968301968a965089955061010090940193600891909101906129d4565b6001600160a01b03168015612b7e57600052600360205260406000205490565b60246040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152fd5b60405190612bbc82611fb4565b6060602083600081520152565b90612bd382612025565b612be06040519182612002565b828152601f19612bf08294612025565b0190602036910137565b80518210156123e25760209160051b010190565b6040519060e0820182811067ffffffffffffffff821117611fd057604052606060c083612c39612baf565b8152600060208201526000604082015282808201528260808201528260a08201520152565b91908201809211612c6b57565b634e487b7160e01b600052601160045260246000fd5b9190612c8e828285612600565b803b612c9b575b50505050565b612cf76001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190611f48565b03906020816000938185885af190829082612dbf575b5050612d5d5782612d1c613aa7565b8051919082612d5657602482604051907f64a0ae920000000000000000000000000000000000000000000000000000000082526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612d8e575038808080612c95565b602490604051907f64a0ae920000000000000000000000000000000000000000000000000000000082526004820152fd5b909192506020813d602011612e18575b81612ddc60209383612002565b8101031261058f5751907fffffffff000000000000000000000000000000000000000000000000000000008216820361094b5750903880612d0d565b3d9150612dcf565b906020612e44610752612e31612c0e565b9385600052600b845260406000206123c6565b8083526001600160a01b03815116608052015192600080612e658651612bc9565b90612e708751612bc9565b91875195601f19612e99612e8389612025565b98612e916040519a8b612002565b808a52612025565b01366020890137612eaa8951612bc9565b976000965b8a518810156133b75763ffffffff612ec7898d612bfa565b51169a604051937f22cd85a80000000000000000000000000000000000000000000000000000000085528c600486015260c0856024816080515afa94851561306957612f7195602091600091613398575b509d604051809781927ff98175c400000000000000000000000000000000000000000000000000000000835288306004850191604091949363ffffffff916001600160a01b036060860197168552602085015216910152565b03816080515afa8015613069578d95600091613341575b506fffffffffffffffffffffffffffffffff169c505b63ffffffff60a086015116156130ac5760049c6fffffffffffffffffffffffffffffffff60408701511690811560001461307557505063ffffffff60a060005b960151166040519d8e7f22cd85a8000000000000000000000000000000000000000000000000000000008152015260c08d6024816080515afa9c8d156130695760a09d63ffffffff9160009161303a575b50959d50612f9e9050565b61305c915060c03d60c011613062575b6130548183612002565b810190613d9c565b3861302f565b503d61304a565b6040513d6000823e3d90fd5b6130a760a09163ffffffff936fffffffffffffffffffffffffffffffff8a511690600190818111908218021891613d19565b612fde565b929a9b98979590939198608083015192604051917f3256cfa90000000000000000000000000000000000000000000000000000000083528460030b600484015260e0836024816080515afa92831561306957600093613316575b508161091f916fffffffffffffffffffffffffffffffff602081604061313b97015116930151169080831083821802186144c6565b926fffffffffffffffffffffffffffffffff604083015116938085108582180218936fffffffffffffffffffffffffffffffff6020818551169401511690600095600094826132f0575b505050506040517fd0c93a7c0000000000000000000000000000000000000000000000000000000081526020816004816080515afa918215613069578f8e938d9360009161327d575b5094613270969461323b85856fffffffffffffffffffffffffffffffff9795613231899761322b60019f9a9d61321f6132659f61320e9060030b83613fd2565b9160018860030b0160030b90613fd2565b908a8c168c8e16614359565b92612bfa565b5260030b92612bfa565b52166132478d8d612bfa565b52166132538b89612bfa565b5261325e8a88612bfa565b5190612c5e565b9561325e8989612bfa565b9601969998909199612eaf565b95969450505090506020833d6020116132e8575b8161329e60209383612002565b81010312611f83576001948f613270958f61323b8f6fffffffffffffffffffffffffffffffff9687956132318361322b6132659d51989d505050509550959a5095505094966131ce565b3d9150613291565b8293975061330c949550918161330692936145ac565b956145ac565b9038808080613185565b61091f9193509161333861313b9360e03d60e011610cca57610cbb8183612002565b93915091613106565b9550506020853d602011613390575b8161335d60209383612002565b81010312611f835763ffffffff60a06fffffffffffffffffffffffffffffffff8f9761338890613536565b925050612f88565b3d9150613350565b6133b1915060c03d60c011613062576130548183612002565b38612f18565b989650509750929490604051907f3ab72c100000000000000000000000000000000000000000000000000000000082526020826004816080515afa918215613069576000926134ae575b50604051907f21272d4c0000000000000000000000000000000000000000000000000000000082526020826004816080515afa91821561306957600092613478575b506134579261345191613e29565b96613e29565b9360c088015260a08701526080860152606085015260408401526020830152565b9091506020813d6020116134a6575b8161349460209383612002565b81010312611f83575190613457613443565b3d9150613487565b9091506020813d6020116134da575b816134ca60209383612002565b81010312611f8357519038613401565b3d91506134bd565b8060005260026020526001600160a01b0360406000205416908115613505575090565b602490604051907f7e2732890000000000000000000000000000000000000000000000000000000082526004820152fd5b51906fffffffffffffffffffffffffffffffff82168203611f8357565b51908160070b8203611f8357565b51908160030b8203611f8357565b51908115158203611f8357565b519063ffffffff82168203611f8357565b519060ff82168203611f8357565b80916101209283910312611f835760405191820182811067ffffffffffffffff821117611fd0576040526135ce81613536565b82526135dc60208201613536565b60208301526135ed60408201613553565b60408301526135fe60608201613553565b6060830152608081015164ffffffffff81168103611f8357608083015261362760a08201613561565b60a083015261363860c0820161356f565b60c083015261364960e0820161357c565b60e083015261365c61010080920161358d565b9082015290565b6001600160a01b038082511691604092835180917f1865c57d0000000000000000000000000000000000000000000000000000000082528160046101209485935afa91821561388d579160e09163ffffffff93600092613870575b50500151169282825116928151937f578eaca400000000000000000000000000000000000000000000000000000000855260048501526020938481602481857f0000000000000000000000000a7e848aca42d879ef06507fca0e7b33a0a63c1e165afa90811561386557600091613830575b501561380757836004918451168351928380927f99013aa80000000000000000000000000000000000000000000000000000000082525afa9081156137fc576000916137c7575b5061379e5750015190620186a0811015613794576125fe91613f25565b506125fe90613e4f565b600490517fdadac8e4000000000000000000000000000000000000000000000000000000008152fd5b90508381813d83116137f5575b6137de8183612002565b81010312611f83576137ef9061356f565b38613777565b503d6137d4565b82513d6000823e3d90fd5b600482517fdd4927b2000000000000000000000000000000000000000000000000000000008152fd5b90508481813d831161385e575b6138478183612002565b81010312611f83576138589061356f565b38613730565b503d61383d565b83513d6000823e3d90fd5b6138869250803d10610cf757610ce88183612002565b38806136be565b85513d6000823e3d90fd5b600090808252600b602092600b60205260409060408120549260019560018511156124b5576138c685612025565b956138d46040519788612002565b858752601f196138e387612025565b01366020890137835b8681106138fe57505050505050505050565b8890828652848452613912818888206123c6565b506001600160a01b0380915416613929838c612bfa565b52865b82811061393b575050016138ec565b9082935061394a81938c612bfa565b511682613957838d612bfa565b511614613969578a01908a929161392c565b6044838984613978838f612bfa565b51169051917f0fdffd6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6001600160a01b03908183168015159081613a48575b50156139ce5750505050565b16613a0457602482604051907f7e2732890000000000000000000000000000000000000000000000000000000082526004820152fd5b6040517f177e802f0000000000000000000000000000000000000000000000000000000081526001600160a01b039190911660048201526024810191909152604490fd5b82841680821492508215613a80575b508115613a66575b50386139c2565b905084600052600460205282604060002054161438613a5f565b909150600052600560205260406000208160005260205260ff604060002054169038613a57565b3d15613ad2573d90613ab88261230f565b91613ac66040519384612002565b82523d6000602084013e565b606090565b60e081830312611f835760405191613aee83611fe6565b613af782613536565b8352602090613b0860208401613536565b6020850152613b1960408401613536565b604085015280607f84011215611f835760405192613b3684611fe6565b839060e08101928311611f8357606001905b828210613b5b5750505050606082015290565b838091613b678461357c565b815201910190613b48565b6fffffffffffffffffffffffffffffffff90818111613b8f571690565b604490604051907f6dfcc650000000000000000000000000000000000000000000000000000000008252608060048301526024820152fd5b90613c065750805115613bdc57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580613c51575b613c17575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b15613c0f565b8115613c64570490565b634e487b7160e01b600052601260045260246000fd5b908082029060001981840990828083109203918083039214613d0857670de0b6b3a76400009082821115613cde577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b60046040517f227bc153000000000000000000000000000000000000000000000000000000008152fd5b5050670de0b6b3a764000091500490565b90918282029160001984820993838086109503948086039514613d8f5784831115613cde5782910981600003821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b5050906121fc9250613c5a565b908160c0910312611f83576040519060c0820182811067ffffffffffffffff821117611fd057613e219160a091604052613dd581613536565b8452613de360208201613536565b6020850152613df460408201613536565b6040850152613e056060820161358d565b6060850152613e1660808201613561565b60808501520161357c565b60a082015290565b90600181148015613e47575b15613e3e575090565b6121fc91613c5a565b508115613e35565b8051906001916001811115613f205760009392916000198201828111845b613e7b575b50505050509050565b80612c6b5781871015613f1b57848701808811612c6b575b848110613ea557509584019584613e6d565b63ffffffff80613eb58a87612bfa565b511681613ec28488612bfa565b511614613ed157508501613e93565b613edb8286612bfa565b516040517f79926e7800000000000000000000000000000000000000000000000000000000815260048101939093521663ffffffff166024820152604490fd5b613e72565b505050565b8051906001926001831115612c955760089060081c60018101809111612c6b57613f4e90612bc9565b9160005b848110613f6157505050505050565b613f6b8183612bfa565b5162ffffff9060ff90613f87838a8484161b92881c1688612bfa565b5116613fc25790613fbb888493613f9f829688612bfa565b519384891c1693161b613fb28389612bfa565b51179187612bfa565b5201613f52565b8263ffffffff613edb8287612bfa565b908060030b90600082126000146143545760000360030b5b63ffffffff80809416911602918216828103612c6b576204eb4a106143235760018216156142fa5770ffffffffffffffffffffffffffffffffff6ffffcb933bd6fad9d3af5f0b9f25db4d65b1690600283166142de575b600483166142c2575b600883166142a6575b6010831661428a575b6020831661426e575b60408316614252575b608092838116614237575b610100811661421c575b6102008116614201575b61040081166141e6575b61080081166141cb575b61100081166141b0575b6120008116614195575b614000811661417a575b618000811661415f575b620100008116614144575b620200008116614129575b620400001661410f575b600012614100575b670de0b6b3a764000002901c90565b8015613c6457600019046140f1565b6d2216e584f630389b2052b8db590e909102821c906140e9565b6e5d6af8dedbcb3a6ccb7ce618d14225909202831c916140df565b916f09aa508b5b7e5a9780b0cc4e25d61a5602831c916140d4565b916f31be135f97da6e09a19dc367e3b6da4002831c916140c9565b916f70d869a156ddd32a39e257bc3f50aa9b02831c916140bf565b916fa9f746462d8f7dd10e744d913d03333302831c916140b5565b916fd097f3bdfd254ee83bdd3f248e7e785e02831c916140ab565b916fe7159475a2c578ef4f1d17b2b235d48002831c916140a1565b916ff3392b0822b88206f8abe8a3b44dd9be02831c91614097565b916ff987a7253ac4d9194200696907cf2e3702831c9161408d565b916ffcbe86c7900aecf64236ab31f1f9dcb502831c91614083565b916ffe5dee046a99d51e2cc356c2f617dbe002831c91614079565b906fff2ea16466c9838804e327cb417cafcb0260801c9061406e565b906fff973b41fa98cd2e57b660be99eb2c4a0260801c90614065565b906fffcb9843d60f67b19e8887e0bd251eb70260801c9061405c565b906fffe5caca7e10e81259b3cddc7a0649410260801c90614053565b906ffff2e50f5f656ac9229c67059486f3890260801c9061404a565b906ffff97272373d41fd789c8cb37ffcaa1c0260801c90614041565b70ffffffffffffffffffffffffffffffffff700100000000000000000000000000000000614036565b602490604051907f20ab18100000000000000000000000000000000000000000000000000000000082526004820152fd5b613fea565b9091928381039160009481604e1c1580614405575b6143f4575b84156143e75781156143d4576143c86143cf956143c285876143bd633b9aca00966143a86143a1858b61447a565b91876144a8565b0160011c976143b78980613c7a565b95613c7a565b613d19565b016144e0565b0201613d19565b901c90565b6143e291506143cf946144a8565b6144c6565b5090506143cf925061447a565b6039955093851b9390851b90614373565b5084604e1c1561436e565b91929390821561447257908185921561446a5761443f614446936144559561443888866144a8565b019361447a565b019061447a565b670de0b6b3a7640000026144e0565b90818111908218021890818110908218021890565b505050505090565b505050905090565b670de0b6b3a76400009081810291831561449f575b8183041490151715611f83570490565b6001935061448f565b818102918183041490151715611f8357670de0b6b3a7640000900490565b81810291831561449f578183041490151715611f83570490565b60b58171010000000000000000000000000000000000811015614595575b80690100000000000000000062010000921015614588575b6501000000000081101561457b575b630100000081101561456e575b010260121c60019080830401811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c8080920410900390565b60101c9160081b91614532565b60201c9160101b91614525565b60401c9160201b91614516565b5068b500000000000000009050608082901c6144fe565b916145e09161091f916fffffffffffffffffffffffffffffffff808092166001811190600118026001189216908516613d19565b81811090821802189056fea2646970667358221220e9fd2457b65203d30ad0388375cd2311f20e2f760422a0cd9b3bfd04dcd0829064736f6c63430008190033

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

000000000000000000000000dbed345273897d2cea8ad530c4c64a922ef98deb0000000000000000000000000a7e848aca42d879ef06507fca0e7b33a0a63c1e

-----Decoded View---------------
Arg [0] : _positionImage (address): 0xDbED345273897D2ceA8aD530c4c64a922eF98DeB
Arg [1] : _factory (address): 0x0A7e848Aca42d879EF06507Fca0E7b33A0a63c1e

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


Block Transaction Gas Used Reward
view all blocks sequenced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
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.