ETH Price: $3,246.64 (+3.64%)
Gas: 3.04 Gwei
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Refund Native To...171251232023-04-25 18:42:23646 days ago1682448143IN
0x36E56CC5...930fF1595
0 ETH0.00310365110
Place Relative O...169723562023-04-04 1:35:59667 days ago1680572159IN
0x36E56CC5...930fF1595
0.5 ETH0.00057724.42042237
Place Relative O...169402802023-03-30 13:12:35672 days ago1680181955IN
0x36E56CC5...930fF1595
0.1 ETH0.0006851928.99913899
Place Maker Orde...169051662023-03-25 14:47:23677 days ago1679755643IN
0x36E56CC5...930fF1595
0 ETH0.0004612520.02301597
Place Maker Orde...169044812023-03-25 12:28:35677 days ago1679747315IN
0x36E56CC5...930fF1595
0.01079591 ETH0.0005344622.87956613
Place Maker Orde...168939272023-03-24 0:55:11678 days ago1679619311IN
0x36E56CC5...930fF1595
0 ETH0.0005207722.25925886
Place Maker Orde...168936742023-03-24 0:03:47678 days ago1679616227IN
0x36E56CC5...930fF1595
0 ETH0.0005141421.97586553
Place Relative O...168832322023-03-22 12:48:11680 days ago1679489291IN
0x36E56CC5...930fF1595
0.45 ETH0.0003575215.13144331
Place Relative O...168832242023-03-22 12:46:35680 days ago1679489195IN
0x36E56CC5...930fF1595
0 ETH0.0003734915.95324332

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block
From
To
171251232023-04-25 18:42:23646 days ago1682448143
0x36E56CC5...930fF1595
1.06079591 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MakerOrderManager

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 100000000 runs

Other Settings:
default evmVersion
File 1 of 23 : MakerOrderManager.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity =0.8.9;
pragma abicoder v2;

import "@openzeppelin/contracts/utils/math/Math.sol";
import "@gridexprotocol/core/contracts/interfaces/IGrid.sol";
import "@gridexprotocol/core/contracts/interfaces/IGridParameters.sol";
import "@gridexprotocol/core/contracts/interfaces/IGridFactory.sol";
import "@gridexprotocol/core/contracts/libraries/GridAddress.sol";
import "@gridexprotocol/core/contracts/libraries/CallbackValidator.sol";
import "@gridexprotocol/core/contracts/libraries/BoundaryMath.sol";
import "./interfaces/IMakerOrderManager.sol";
import "./interfaces/IRelativeOrderManager.sol";
import "./Multicall.sol";
import "./AbstractPayments.sol";
import "./AbstractSelfPermit2612.sol";

/// @title The implementation for the maker order manager
contract MakerOrderManager is
    IMakerOrderManager,
    IRelativeOrderManager,
    AbstractPayments,
    AbstractSelfPermit2612,
    Multicall
{
    constructor(address _gridFactory, address _weth9) AbstractPayments(_gridFactory, _weth9) {}

    struct PlaceMakerOrderCalldata {
        GridAddress.GridKey gridKey;
        address payer;
    }

    /// @inheritdoc IGridPlaceMakerOrderCallback
    function gridexPlaceMakerOrderCallback(uint256 amount0, uint256 amount1, bytes calldata data) external override {
        PlaceMakerOrderCalldata memory decodeData = abi.decode(data, (PlaceMakerOrderCalldata));
        CallbackValidator.validate(gridFactory, decodeData.gridKey);

        if (amount0 > 0) pay(decodeData.gridKey.token0, decodeData.payer, _msgSender(), amount0);

        if (amount1 > 0) pay(decodeData.gridKey.token1, decodeData.payer, _msgSender(), amount1);
    }

    /// @inheritdoc IMakerOrderManager
    function initialize(InitializeParameters calldata parameters) external payable {
        GridAddress.GridKey memory gridKey = GridAddress.gridKey(
            parameters.tokenA,
            parameters.tokenB,
            parameters.resolution
        );
        address grid = GridAddress.computeAddress(gridFactory, gridKey);

        address recipient = parameters.recipient == address(0) ? _msgSender() : parameters.recipient;

        IGrid(grid).initialize(
            IGridParameters.InitializeParameters({
                priceX96: parameters.priceX96,
                recipient: recipient,
                orders0: parameters.orders0,
                orders1: parameters.orders1
            }),
            abi.encode(PlaceMakerOrderCalldata({gridKey: gridKey, payer: _msgSender()}))
        );
    }

    /// @inheritdoc IMakerOrderManager
    function createGridAndInitialize(InitializeParameters calldata parameters) external payable {
        address grid = IGridFactory(gridFactory).createGrid(
            parameters.tokenA,
            parameters.tokenB,
            parameters.resolution
        );

        address recipient = parameters.recipient == address(0) ? _msgSender() : parameters.recipient;

        IGrid(grid).initialize(
            IGridParameters.InitializeParameters({
                priceX96: parameters.priceX96,
                recipient: recipient,
                orders0: parameters.orders0,
                orders1: parameters.orders1
            }),
            abi.encode(
                PlaceMakerOrderCalldata({
                    gridKey: GridAddress.gridKey(parameters.tokenA, parameters.tokenB, parameters.resolution),
                    payer: _msgSender()
                })
            )
        );
    }

    /// @inheritdoc IMakerOrderManager
    function placeMakerOrder(
        PlaceOrderParameters calldata parameters
    ) external payable checkDeadline(parameters.deadline) returns (uint256 orderId) {
        GridAddress.GridKey memory gridKey = GridAddress.gridKey(
            parameters.tokenA,
            parameters.tokenB,
            parameters.resolution
        );
        address grid = GridAddress.computeAddress(gridFactory, gridKey);

        address recipient = parameters.recipient == address(0) ? _msgSender() : parameters.recipient;

        orderId = _placeMakerOrder(
            grid,
            gridKey,
            recipient,
            parameters.zero,
            parameters.boundaryLower,
            parameters.amount
        );
    }

    function _placeMakerOrder(
        address grid,
        GridAddress.GridKey memory gridKey,
        address recipient,
        bool zero,
        int24 boundaryLower,
        uint128 amount
    ) private returns (uint256 orderId) {
        orderId = IGrid(grid).placeMakerOrder(
            IGridParameters.PlaceOrderParameters({
                recipient: recipient,
                zero: zero,
                boundaryLower: boundaryLower,
                amount: amount
            }),
            abi.encode(PlaceMakerOrderCalldata({gridKey: gridKey, payer: _msgSender()}))
        );
    }

    /// @inheritdoc IMakerOrderManager
    function placeMakerOrderInBatch(
        PlaceOrderInBatchParameters calldata parameters
    ) external payable checkDeadline(parameters.deadline) returns (uint256[] memory orderIds) {
        GridAddress.GridKey memory gridKey = GridAddress.gridKey(
            parameters.tokenA,
            parameters.tokenB,
            parameters.resolution
        );
        address grid = GridAddress.computeAddress(gridFactory, gridKey);

        address recipient = parameters.recipient == address(0) ? _msgSender() : parameters.recipient;

        orderIds = IGrid(grid).placeMakerOrderInBatch(
            IGridParameters.PlaceOrderInBatchParameters({
                recipient: recipient,
                zero: parameters.zero,
                orders: parameters.orders
            }),
            abi.encode(PlaceMakerOrderCalldata({gridKey: gridKey, payer: _msgSender()}))
        );
    }

    /// @inheritdoc IRelativeOrderManager
    function placeRelativeOrder(
        RelativeOrderParameters calldata parameters
    ) external payable checkDeadline(parameters.deadline) returns (uint256 orderId) {
        // MOM_AIZ: amount is zero
        require(parameters.amount > 0, "MOM_AIZ");

        GridAddress.GridKey memory gridKey = GridAddress.gridKey(
            parameters.tokenA,
            parameters.tokenB,
            parameters.resolution
        );
        address grid = GridAddress.computeAddress(gridFactory, gridKey);

        (uint160 priceX96, , , ) = IGrid(grid).slot0();
        uint160 targetPriceX96 = parameters.priceDeltaX96 > 0
            ? priceX96 + uint160(parameters.priceDeltaX96)
            : priceX96 - uint160(-parameters.priceDeltaX96);

        // MOM_POR: price out of range
        require(BoundaryMath.isPriceX96InRange(targetPriceX96), "MOM_POR");
        require(
            targetPriceX96 >= parameters.priceMinimumX96 && targetPriceX96 <= parameters.priceMaximumX96,
            "MOM_POR"
        );

        int24 boundaryLower = BoundaryMath.rewriteToValidBoundaryLower(
            BoundaryMath.getBoundaryLowerAtBoundary(
                BoundaryMath.getBoundaryAtPriceX96(targetPriceX96),
                parameters.resolution
            ),
            parameters.resolution
        );

        // when the input is token1 and the price has reached the right boundary price,
        // we need to subtract a resolution from boundary lower
        if (!parameters.zero) {
            uint160 priceMaxX96 = BoundaryMath.getPriceX96AtBoundary(boundaryLower);
            boundaryLower = priceMaxX96 == targetPriceX96
                ? BoundaryMath.rewriteToValidBoundaryLower(
                    boundaryLower -= parameters.resolution,
                    parameters.resolution
                ) // avoid underflow
                : boundaryLower;
        }

        address recipient = parameters.recipient == address(0) ? _msgSender() : parameters.recipient;

        orderId = _placeMakerOrder(grid, gridKey, recipient, parameters.zero, boundaryLower, parameters.amount);
    }
}

File 2 of 23 : IGridPlaceMakerOrderCallback.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

/// @title Callback for IGrid#placeMakerOrder
/// @notice Any contract that calls IGrid#placeMakerOrder must implement this interface
interface IGridPlaceMakerOrderCallback {
    /// @notice Called to `msg.sender` after executing a place maker order via IGrid#placeMakerOrder
    /// @dev In this implementation, you are required to pay the grid tokens owed for the maker order.
    /// The caller of the method must be a grid deployed by the canonical GridFactory.
    /// At most one of amount0 and amount1 is a positive number
    /// @param amount0 The grid will receive the amount of token0 upon placement of the maker order.
    /// In the receiving case, the callback must send this amount of token0 to the grid
    /// @param amount1 The grid will receive the amount of token1 upon placement of the maker order.
    /// In the receiving case, the callback must send this amount of token1 to the grid
    /// @param data Any data passed through by the caller via the IGrid#placeMakerOrder call
    function gridexPlaceMakerOrderCallback(uint256 amount0, uint256 amount1, bytes calldata data) external;
}

File 3 of 23 : IGrid.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import "./IGridStructs.sol";
import "./IGridParameters.sol";

/// @title The interface for Gridex grid
interface IGrid {
    ///==================================== Grid States  ====================================

    /// @notice The first token in the grid, after sorting by address
    function token0() external view returns (address);

    /// @notice The second token in the grid, after sorting by address
    function token1() external view returns (address);

    /// @notice The step size in initialized boundaries for a grid created with a given fee
    function resolution() external view returns (int24);

    /// @notice The fee paid to the grid denominated in hundredths of a bip, i.e. 1e-6
    function takerFee() external view returns (int24);

    /// @notice The 0th slot of the grid holds a lot of values that can be gas-efficiently accessed
    /// externally as a single method
    /// @return priceX96 The current price of the grid, as a Q64.96
    /// @return boundary The current boundary of the grid
    /// @return blockTimestamp The time the oracle was last updated
    /// @return unlocked Whether the grid is unlocked or not
    function slot0() external view returns (uint160 priceX96, int24 boundary, uint32 blockTimestamp, bool unlocked);

    /// @notice Returns the boundary information of token0
    /// @param boundary The boundary of the grid
    /// @return bundle0Id The unique identifier of bundle0
    /// @return bundle1Id The unique identifier of bundle1
    /// @return makerAmountRemaining The remaining amount of token0 that can be swapped out,
    /// which is the sum of bundle0 and bundle1
    function boundaries0(
        int24 boundary
    ) external view returns (uint64 bundle0Id, uint64 bundle1Id, uint128 makerAmountRemaining);

    /// @notice Returns the boundary information of token1
    /// @param boundary The boundary of the grid
    /// @return bundle0Id The unique identifier of bundle0
    /// @return bundle1Id The unique identifier of bundle1
    /// @return makerAmountRemaining The remaining amount of token1 that can be swapped out,
    /// which is the sum of bundle0 and bundle1
    function boundaries1(
        int24 boundary
    ) external view returns (uint64 bundle0Id, uint64 bundle1Id, uint128 makerAmountRemaining);

    /// @notice Returns 256 packed boundary initialized boolean values for token0
    function boundaryBitmaps0(int16 wordPos) external view returns (uint256 word);

    /// @notice Returns 256 packed boundary initialized boolean values for token1
    function boundaryBitmaps1(int16 wordPos) external view returns (uint256 word);

    /// @notice Returns the amount owed for token0 and token1
    /// @param owner The address of owner
    /// @return token0 The amount of token0 owed
    /// @return token1 The amount of token1 owed
    function tokensOweds(address owner) external view returns (uint128 token0, uint128 token1);

    /// @notice Returns the information of a given bundle
    /// @param bundleId The unique identifier of the bundle
    /// @return boundaryLower The lower boundary of the bundle
    /// @return zero When zero is true, it represents token0, otherwise it represents token1
    /// @return makerAmountTotal The total amount of token0 or token1 that the maker added
    /// @return makerAmountRemaining The remaining amount of token0 or token1 that can be swapped out from the makers
    /// @return takerAmountRemaining The remaining amount of token0 or token1 that have been swapped in from the takers
    /// @return takerFeeAmountRemaining The remaining amount of fees that takers have paid in
    function bundles(
        uint64 bundleId
    )
        external
        view
        returns (
            int24 boundaryLower,
            bool zero,
            uint128 makerAmountTotal,
            uint128 makerAmountRemaining,
            uint128 takerAmountRemaining,
            uint128 takerFeeAmountRemaining
        );

    /// @notice Returns the information of a given order
    /// @param orderId The unique identifier of the order
    /// @return bundleId The unique identifier of the bundle -- represents which bundle this order belongs to
    /// @return owner The address of the owner of the order
    /// @return amount The amount of token0 or token1 to add
    function orders(uint256 orderId) external view returns (uint64 bundleId, address owner, uint128 amount);

    ///==================================== Grid Actions ====================================

    /// @notice Initializes the grid with the given parameters
    /// @dev The caller of this method receives a callback in the form of
    /// IGridPlaceMakerOrderCallback#gridexPlaceMakerOrderCallback.
    /// When initializing the grid, token0 and token1's liquidity must be added simultaneously.
    /// @param parameters The parameters used to initialize the grid
    /// @param data Any data to be passed through to the callback
    /// @return orderIds0 The unique identifiers of the orders for token0
    /// @return orderIds1 The unique identifiers of the orders for token1
    function initialize(
        IGridParameters.InitializeParameters memory parameters,
        bytes calldata data
    ) external returns (uint256[] memory orderIds0, uint256[] memory orderIds1);

    /// @notice Swaps token0 for token1, or vice versa
    /// @dev The caller of this method receives a callback in the form of IGridSwapCallback#gridexSwapCallback
    /// @param recipient The address to receive the output of the swap
    /// @param zeroForOne The swap direction, true for token0 to token1 and false otherwise
    /// @param amountSpecified The amount of the swap, configured as an exactInput (positive)
    /// or an exactOutput (negative)
    /// @param priceLimitX96 Swap price limit: if zeroForOne, the price will not be less than this value after swap,
    /// if oneForZero, it will not be greater than this value after swap, as a Q64.96
    /// @param data Any data to be passed through to the callback
    /// @return amount0 The balance change of the grid's token0. When negative, it will reduce the balance
    /// by the exact amount. When positive, it will increase by at least this amount
    /// @return amount1 The balance change of the grid's token1. When negative, it will reduce the balance
    /// by the exact amount. When positive, it will increase by at least this amount.
    function swap(
        address recipient,
        bool zeroForOne,
        int256 amountSpecified,
        uint160 priceLimitX96,
        bytes calldata data
    ) external returns (int256 amount0, int256 amount1);

    /// @notice Places a maker order on the grid
    /// @dev The caller of this method receives a callback in the form of
    /// IGridPlaceMakerOrderCallback#gridexPlaceMakerOrderCallback
    /// @param parameters The parameters used to place the maker order
    /// @param data Any data to be passed through to the callback
    /// @return orderId The unique identifier of the order
    function placeMakerOrder(
        IGridParameters.PlaceOrderParameters memory parameters,
        bytes calldata data
    ) external returns (uint256 orderId);

    /// @notice Places maker orders on the grid
    /// @dev The caller of this method receives a callback in the form of
    /// IGridPlaceMakerOrderCallback#gridexPlaceMakerOrderCallback
    /// @param parameters The parameters used to place the maker orders
    /// @param data Any data to be passed through to the callback
    /// @return orderIds The unique identifiers of the orders
    function placeMakerOrderInBatch(
        IGridParameters.PlaceOrderInBatchParameters memory parameters,
        bytes calldata data
    ) external returns (uint256[] memory orderIds);

    /// @notice Settles a maker order
    /// @param orderId The unique identifier of the order
    /// @return amount0 The amount of token0 that the maker received
    /// @return amount1 The amount of token1 that the maker received
    function settleMakerOrder(uint256 orderId) external returns (uint128 amount0, uint128 amount1);

    /// @notice Settle maker order and collect
    /// @param recipient The address to receive the output of the settlement
    /// @param orderId The unique identifier of the order
    /// @param unwrapWETH9 Whether to unwrap WETH9 to ETH
    /// @return amount0 The amount of token0 that the maker received
    /// @return amount1 The amount of token1 that the maker received
    function settleMakerOrderAndCollect(
        address recipient,
        uint256 orderId,
        bool unwrapWETH9
    ) external returns (uint128 amount0, uint128 amount1);

    /// @notice Settles maker orders and collects in a batch
    /// @param recipient The address to receive the output of the settlement
    /// @param orderIds The unique identifiers of the orders
    /// @param unwrapWETH9 Whether to unwrap WETH9 to ETH
    /// @return amount0Total The total amount of token0 that the maker received
    /// @return amount1Total The total amount of token1 that the maker received
    function settleMakerOrderAndCollectInBatch(
        address recipient,
        uint256[] memory orderIds,
        bool unwrapWETH9
    ) external returns (uint128 amount0Total, uint128 amount1Total);

    /// @notice For flash swaps. The caller borrows assets and returns them in the callback of the function,
    /// in addition to a fee
    /// @dev The caller of this function receives a callback in the form of IGridFlashCallback#gridexFlashCallback
    /// @param recipient The address which will receive the token0 and token1
    /// @param amount0 The amount of token0 to receive
    /// @param amount1 The amount of token1 to receive
    /// @param data Any data to be passed through to the callback
    function flash(address recipient, uint256 amount0, uint256 amount1, bytes calldata data) external;

    /// @notice Collects tokens owed
    /// @param recipient The address to receive the collected fees
    /// @param amount0Requested The maximum amount of token0 to send.
    /// Set to 0 if fees should only be collected in token1.
    /// @param amount1Requested The maximum amount of token1 to send.
    /// Set to 0 if fees should only be collected in token0.
    /// @return amount0 The amount of fees collected in token0
    /// @return amount1 The amount of fees collected in token1
    function collect(
        address recipient,
        uint128 amount0Requested,
        uint128 amount1Requested
    ) external returns (uint128 amount0, uint128 amount1);
}

File 4 of 23 : IGridFactory.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

/// @title The interface for Gridex grid factory
interface IGridFactory {
    /// @notice Emitted when a new resolution is enabled for grid creation via the grid factory
    /// @param resolution The step size in initialized boundaries for a grid created with a given fee
    /// @param takerFee The taker fee, denominated in hundredths of a bip (i.e. 1e-6)
    event ResolutionEnabled(int24 indexed resolution, int24 indexed takerFee);

    /// @notice Emitted upon grid creation
    /// @param token0 The first token in the grid, after sorting by address
    /// @param token1 The first token in the grid, after sorting by address
    /// @param resolution The step size in initialized boundaries for a grid created with a given fee
    /// @param grid The address of the deployed grid
    event GridCreated(address indexed token0, address indexed token1, int24 indexed resolution, address grid);

    /// @notice Returns the taker fee for the given resolution if enabled. Else, returns 0.
    /// @dev A resolution can never be removed, so this value should be hard coded or cached in the calling context
    /// @param resolution The enabled resolution
    /// @return takerFee The taker fee, denominated in hundredths of a bip (i.e. 1e-6)
    function resolutions(int24 resolution) external view returns (int24 takerFee);

    /// @notice The implementation address of the price oracle
    function priceOracle() external view returns (address);

    /// @notice Returns the grid address for a given token pair and a resolution. Returns 0 if the pair does not exist.
    /// @dev tokenA and tokenB may be passed in, in the order of either token0/token1 or token1/token0
    /// @param tokenA The contract address of either token0 or token1
    /// @param tokenB The contract address of the other token
    /// @param resolution The step size in initialized boundaries for a grid created with a given fee
    /// @return grid The grid address
    function grids(address tokenA, address tokenB, int24 resolution) external view returns (address grid);

    /// @notice Concat grid creation code bytes
    /// @dev Split the creationCode of the Grid contract into two parts, so that the Gas Limit of particular networks can be met when deploying.
    /// @param gridSuffixCreationCode This parameter is the second half of the creationCode of the Grid contract.
    function concatGridSuffixCreationCode(bytes memory gridSuffixCreationCode) external;

    /// @notice Creates a grid for a given pair of tokens and resolution
    /// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0.
    /// @param tokenA One token of the grid token pair
    /// @param tokenB The other token of the grid token pair
    /// @param resolution The step size in initialized boundaries for a grid created with a given fee
    /// @return grid The address of the deployed grid
    function createGrid(address tokenA, address tokenB, int24 resolution) external returns (address grid);
}

File 5 of 23 : IGridParameters.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

interface IGridParameters {
    /// @dev Parameters for initializing the grid
    struct InitializeParameters {
        /// @dev The initial price of the grid, as a Q64.96.
        /// Price is represented as an amountToken1/amountToken0 Q64.96 value.
        uint160 priceX96;
        /// @dev The address to receive orders
        address recipient;
        /// @dev Represents the order parameters for token0
        BoundaryLowerWithAmountParameters[] orders0;
        /// @dev Represents the order parameters for token1
        BoundaryLowerWithAmountParameters[] orders1;
    }

    /// @dev Parameters for placing an order
    struct PlaceOrderParameters {
        /// @dev The address to receive the order
        address recipient;
        /// @dev When zero is true, it represents token0, otherwise it represents token1
        bool zero;
        /// @dev The lower boundary of the order
        int24 boundaryLower;
        /// @dev The amount of token0 or token1 to add
        uint128 amount;
    }

    struct PlaceOrderInBatchParameters {
        /// @dev The address to receive the order
        address recipient;
        /// @dev When zero is true, it represents token0, otherwise it represents token1
        bool zero;
        BoundaryLowerWithAmountParameters[] orders;
    }

    struct BoundaryLowerWithAmountParameters {
        /// @dev The lower boundary of the order
        int24 boundaryLower;
        /// @dev The amount of token0 or token1 to add
        uint128 amount;
    }

    /// @dev Status during swap
    struct SwapState {
        /// @dev When true, token0 is swapped for token1, otherwise token1 is swapped for token0
        bool zeroForOne;
        /// @dev The remaining amount of the swap, which implicitly configures
        /// the swap as exact input (positive), or exact output (negative)
        int256 amountSpecifiedRemaining;
        /// @dev The calculated amount to be inputted
        uint256 amountInputCalculated;
        /// @dev The calculated amount of fee to be inputted
        uint256 feeAmountInputCalculated;
        /// @dev The calculated amount to be outputted
        uint256 amountOutputCalculated;
        /// @dev The price of the grid, as a Q64.96
        uint160 priceX96;
        uint160 priceLimitX96;
        /// @dev The boundary of the grid
        int24 boundary;
        /// @dev The lower boundary of the grid
        int24 boundaryLower;
        uint160 initializedBoundaryLowerPriceX96;
        uint160 initializedBoundaryUpperPriceX96;
        /// @dev Whether the swap has been completed
        bool stopSwap;
    }

    struct SwapForBoundaryState {
        /// @dev The price indicated by the lower boundary, as a Q64.96
        uint160 boundaryLowerPriceX96;
        /// @dev The price indicated by the upper boundary, as a Q64.96
        uint160 boundaryUpperPriceX96;
        /// @dev The price indicated by the lower or upper boundary, as a Q64.96.
        /// When using token0 to exchange token1, it is equal to boundaryLowerPriceX96,
        /// otherwise it is equal to boundaryUpperPriceX96
        uint160 boundaryPriceX96;
        /// @dev The price of the grid, as a Q64.96
        uint160 priceX96;
    }

    struct UpdateBundleForTakerParameters {
        /// @dev The amount to be swapped in to bundle0
        uint256 amountInUsed;
        /// @dev The remaining amount to be swapped in to bundle1
        uint256 amountInRemaining;
        /// @dev The amount to be swapped out to bundle0
        uint128 amountOutUsed;
        /// @dev The remaining amount to be swapped out to bundle1
        uint128 amountOutRemaining;
        /// @dev The amount to be paid to bundle0
        uint128 takerFeeForMakerAmountUsed;
        /// @dev The amount to be paid to bundle1
        uint128 takerFeeForMakerAmountRemaining;
    }
}

File 6 of 23 : IGridStructs.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

interface IGridStructs {
    struct Bundle {
        int24 boundaryLower;
        bool zero;
        uint128 makerAmountTotal;
        uint128 makerAmountRemaining;
        uint128 takerAmountRemaining;
        uint128 takerFeeAmountRemaining;
    }

    struct Boundary {
        uint64 bundle0Id;
        uint64 bundle1Id;
        uint128 makerAmountRemaining;
    }

    struct Order {
        uint64 bundleId;
        address owner;
        uint128 amount;
    }

    struct TokensOwed {
        uint128 token0;
        uint128 token1;
    }

    struct Slot0 {
        uint160 priceX96;
        int24 boundary;
        uint32 blockTimestamp;
        bool unlocked;
    }
}

File 7 of 23 : IWETHMinimum.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

interface IWETHMinimum {
    function deposit() external payable;

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

    function withdraw(uint256) external;

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

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

File 8 of 23 : BoundaryMath.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

library BoundaryMath {
    int24 public constant MIN_BOUNDARY = -527400;
    int24 public constant MAX_BOUNDARY = 443635;

    /// @dev The minimum value that can be returned from #getPriceX96AtBoundary. Equivalent to getPriceX96AtBoundary(MIN_BOUNDARY)
    uint160 internal constant MIN_RATIO = 989314;
    /// @dev The maximum value that can be returned from #getPriceX96AtBoundary. Equivalent to getPriceX96AtBoundary(MAX_BOUNDARY)
    uint160 internal constant MAX_RATIO = 1461300573427867316570072651998408279850435624081;

    /// @dev Checks if a boundary is divisible by a resolution
    /// @param boundary The boundary to check
    /// @param resolution The step size in initialized boundaries for a grid created with a given fee
    /// @return isValid Whether or not the boundary is valid
    function isValidBoundary(int24 boundary, int24 resolution) internal pure returns (bool isValid) {
        return boundary % resolution == 0;
    }

    /// @dev Checks if a boundary is within the valid range
    /// @param boundary The boundary to check
    /// @return inRange Whether or not the boundary is in range
    function isInRange(int24 boundary) internal pure returns (bool inRange) {
        return boundary >= MIN_BOUNDARY && boundary <= MAX_BOUNDARY;
    }

    /// @dev Checks if a price is within the valid range
    /// @param priceX96 The price to check, as a Q64.96
    /// @return inRange Whether or not the price is in range
    function isPriceX96InRange(uint160 priceX96) internal pure returns (bool inRange) {
        return priceX96 >= MIN_RATIO && priceX96 <= MAX_RATIO;
    }

    /// @notice Calculates the price at a given boundary
    /// @dev priceX96 = pow(1.0001, boundary) * 2**96
    /// @param boundary The boundary to calculate the price at
    /// @return priceX96 The price at the boundary, as a Q64.96
    function getPriceX96AtBoundary(int24 boundary) internal pure returns (uint160 priceX96) {
        unchecked {
            uint256 absBoundary = boundary < 0 ? uint256(-int256(boundary)) : uint24(boundary);

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

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

            // this divides by 1<<32 and rounds up to go from a Q128.128 to a Q128.96.
            // due to out boundary input limitations, we then proceed to downcast as the
            // result will always fit within 160 bits.
            // we round up in the division so that getBoundaryAtPriceX96 of the output price is always consistent
            priceX96 = uint160((ratio + 0xffffffff) >> 32);
        }
    }

    /// @notice Calculates the boundary at a given price
    /// @param priceX96 The price to calculate the boundary at, as a Q64.96
    /// @return boundary The boundary at the price
    function getBoundaryAtPriceX96(uint160 priceX96) internal pure returns (int24 boundary) {
        unchecked {
            uint256 ratio = uint256(priceX96) << 32;

            uint256 r = ratio;
            uint256 msb = 0;

            assembly {
                let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
                msb := or(msb, f)
                r := shr(f, r)
            }
            assembly {
                let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
                msb := or(msb, f)
                r := shr(f, r)
            }
            assembly {
                let f := shl(5, gt(r, 0xFFFFFFFF))
                msb := or(msb, f)
                r := shr(f, r)
            }
            assembly {
                let f := shl(4, gt(r, 0xFFFF))
                msb := or(msb, f)
                r := shr(f, r)
            }
            assembly {
                let f := shl(3, gt(r, 0xFF))
                msb := or(msb, f)
                r := shr(f, r)
            }
            assembly {
                let f := shl(2, gt(r, 0xF))
                msb := or(msb, f)
                r := shr(f, r)
            }
            assembly {
                let f := shl(1, gt(r, 0x3))
                msb := or(msb, f)
                r := shr(f, r)
            }
            assembly {
                let f := gt(r, 0x1)
                msb := or(msb, f)
            }

            if (msb >= 128) r = ratio >> (msb - 127);
            else r = ratio << (127 - msb);

            int256 log_2 = (int256(msb) - 128) << 64;

            assembly {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(63, f))
                r := shr(f, r)
            }
            assembly {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(62, f))
                r := shr(f, r)
            }
            assembly {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(61, f))
                r := shr(f, r)
            }
            assembly {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(60, f))
                r := shr(f, r)
            }
            assembly {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(59, f))
                r := shr(f, r)
            }
            assembly {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(58, f))
                r := shr(f, r)
            }
            assembly {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(57, f))
                r := shr(f, r)
            }
            assembly {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(56, f))
                r := shr(f, r)
            }
            assembly {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(55, f))
                r := shr(f, r)
            }
            assembly {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(54, f))
                r := shr(f, r)
            }
            assembly {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(53, f))
                r := shr(f, r)
            }
            assembly {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(52, f))
                r := shr(f, r)
            }
            assembly {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(51, f))
                r := shr(f, r)
            }
            assembly {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(50, f))
            }

            int256 log10001 = log_2 * 127869479499801913173570;
            // 128.128 number

            int24 boundaryLow = int24((log10001 - 1701496478404566090792001455681771637) >> 128);
            int24 boundaryHi = int24((log10001 + 289637967442836604689790891002483458648) >> 128);

            boundary = boundaryLow == boundaryHi ? boundaryLow : getPriceX96AtBoundary(boundaryHi) <= priceX96
                ? boundaryHi
                : boundaryLow;
        }
    }

    /// @dev Returns the lower boundary for the given boundary and resolution.
    /// The lower boundary may not be valid (if out of the boundary range)
    /// @param boundary The boundary to get the lower boundary for
    /// @param resolution The step size in initialized boundaries for a grid created with a given fee
    /// @return boundaryLower The lower boundary for the given boundary and resolution
    function getBoundaryLowerAtBoundary(int24 boundary, int24 resolution) internal pure returns (int24 boundaryLower) {
        unchecked {
            return boundary - (((boundary % resolution) + resolution) % resolution);
        }
    }

    /// @dev Rewrite the lower boundary that is not in the range to a valid value
    /// @param boundaryLower The lower boundary to rewrite
    /// @param resolution The step size in initialized boundaries for a grid created with a given fee
    /// @return validBoundaryLower The valid lower boundary
    function rewriteToValidBoundaryLower(
        int24 boundaryLower,
        int24 resolution
    ) internal pure returns (int24 validBoundaryLower) {
        unchecked {
            if (boundaryLower < MIN_BOUNDARY) return boundaryLower + resolution;
            else if (boundaryLower + resolution > MAX_BOUNDARY) return boundaryLower - resolution;
            else return boundaryLower;
        }
    }
}

File 9 of 23 : CallbackValidator.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import "./GridAddress.sol";

library CallbackValidator {
    /// @dev Validates the `msg.sender` is the canonical grid address for the given parameters
    /// @param gridFactory The address of the grid factory
    /// @param gridKey The grid key to compute the canonical address for the grid
    function validate(address gridFactory, GridAddress.GridKey memory gridKey) internal view {
        // CV_IC: invalid caller
        require(GridAddress.computeAddress(gridFactory, gridKey) == msg.sender, "CV_IC");
    }
}

File 10 of 23 : GridAddress.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/Create2.sol";

library GridAddress {
    bytes32 internal constant GRID_BYTES_CODE_HASH = 0x884a6891a166f885bf6f0a3b330a25e41d1761a5aa091110a229d9a0e34b2c36;

    struct GridKey {
        address token0;
        address token1;
        int24 resolution;
    }

    /// @notice Constructs the grid key for the given parameters
    /// @dev tokenA and tokenB may be passed in, in the order of either token0/token1 or token1/token0
    /// @param tokenA The contract address of either token0 or token1
    /// @param tokenB The contract address of the other token
    /// @param resolution The step size in initialized boundaries for a grid created with a given fee
    /// @return key The grid key to compute the canonical address for the grid
    function gridKey(address tokenA, address tokenB, int24 resolution) internal pure returns (GridKey memory key) {
        if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA);

        return GridKey(tokenA, tokenB, resolution);
    }

    /// @dev Computes the CREATE2 address for a grid with the given parameters
    /// @param gridFactory The address of the grid factory
    /// @param key The grid key to compute the canonical address for the grid
    /// @return grid The computed address
    function computeAddress(address gridFactory, GridKey memory key) internal pure returns (address grid) {
        require(key.token0 < key.token1);
        return
            Create2.computeAddress(
                keccak256(abi.encode(key.token0, key.token1, key.resolution)),
                GRID_BYTES_CODE_HASH,
                gridFactory
            );
    }
}

File 11 of 23 : draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 12 of 23 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @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 amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` 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 amount
    ) external returns (bool);
}

File 13 of 23 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 14 of 23 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @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, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * 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.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @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`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

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

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) 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(errorMessage);
        }
    }
}

File 15 of 23 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

File 16 of 23 : Create2.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Create2.sol)

pragma solidity ^0.8.0;

/**
 * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
 * `CREATE2` can be used to compute in advance the address where a smart
 * contract will be deployed, which allows for interesting new mechanisms known
 * as 'counterfactual interactions'.
 *
 * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
 * information.
 */
library Create2 {
    /**
     * @dev Deploys a contract using `CREATE2`. The address where the contract
     * will be deployed can be known in advance via {computeAddress}.
     *
     * The bytecode for a contract can be obtained from Solidity with
     * `type(contractName).creationCode`.
     *
     * Requirements:
     *
     * - `bytecode` must not be empty.
     * - `salt` must have not been used for `bytecode` already.
     * - the factory must have a balance of at least `amount`.
     * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
     */
    function deploy(
        uint256 amount,
        bytes32 salt,
        bytes memory bytecode
    ) internal returns (address addr) {
        require(address(this).balance >= amount, "Create2: insufficient balance");
        require(bytecode.length != 0, "Create2: bytecode length is zero");
        /// @solidity memory-safe-assembly
        assembly {
            addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
        }
        require(addr != address(0), "Create2: Failed on deploy");
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
     * `bytecodeHash` or `salt` will result in a new destination address.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
        return computeAddress(salt, bytecodeHash, address(this));
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
     * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
     */
    function computeAddress(
        bytes32 salt,
        bytes32 bytecodeHash,
        address deployer
    ) internal pure returns (address addr) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40) // Get free memory pointer

            // |                   | ↓ ptr ...  ↓ ptr + 0x0B (start) ...  ↓ ptr + 0x20 ...  ↓ ptr + 0x40 ...   |
            // |-------------------|---------------------------------------------------------------------------|
            // | bytecodeHash      |                                                        CCCCCCCCCCCCC...CC |
            // | salt              |                                      BBBBBBBBBBBBB...BB                   |
            // | deployer          | 000000...0000AAAAAAAAAAAAAAAAAAA...AA                                     |
            // | 0xFF              |            FF                                                             |
            // |-------------------|---------------------------------------------------------------------------|
            // | memory            | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
            // | keccak(start, 85) |            ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |

            mstore(add(ptr, 0x40), bytecodeHash)
            mstore(add(ptr, 0x20), salt)
            mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
            let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
            mstore8(start, 0xff)
            addr := keccak256(start, 85)
        }
    }
}

File 17 of 23 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @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 up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (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; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

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

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            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 (rounding == Rounding.Up && 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 down.
     *
     * 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 + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * 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 + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * 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 + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * 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 10, 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 + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
        }
    }
}

File 18 of 23 : AbstractPayments.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@gridexprotocol/core/contracts/interfaces/IWETHMinimum.sol";
import "./interfaces/IPayments.sol";

abstract contract AbstractPayments is IPayments, Context {
    /// @dev The address of IGridFactory
    address public immutable gridFactory;
    /// @dev The address of IWETHMinimum
    address public immutable weth9;

    constructor(address _gridFactory, address _weth9) {
        // AP_NC: not contract
        require(Address.isContract(_gridFactory), "AP_NC");
        require(Address.isContract(_weth9), "AP_NC");

        gridFactory = _gridFactory;
        weth9 = _weth9;
    }

    modifier checkDeadline(uint256 deadline) {
        // AP_TTO: transaction too old
        require(block.timestamp <= deadline, "AP_TTO");
        _;
    }

    receive() external payable {
        // AP_WETH9: not WETH9
        require(_msgSender() == weth9, "AP_WETH9");
    }

    /// @inheritdoc IPayments
    function unwrapWETH9(uint256 amountMinimum, address recipient) public payable override {
        uint256 balanceWETH9 = IWETHMinimum(weth9).balanceOf(address(this));
        // AP_IWETH9: insufficient WETH9
        require(balanceWETH9 >= amountMinimum, "AP_IWETH9");

        if (balanceWETH9 > 0) {
            IWETHMinimum(weth9).withdraw(balanceWETH9);
            Address.sendValue(payable(recipient), balanceWETH9);
        }
    }

    /// @inheritdoc IPayments
    function sweepToken(address token, uint256 amountMinimum, address recipient) public payable override {
        uint256 balanceToken = IERC20(token).balanceOf(address(this));
        // AP_ITKN: insufficient token
        require(balanceToken >= amountMinimum, "AP_ITKN");

        if (balanceToken > 0) SafeERC20.safeTransfer(IERC20(token), recipient, balanceToken);
    }

    /// @inheritdoc IPayments
    function refundNativeToken() external payable {
        if (address(this).balance > 0) Address.sendValue(payable(_msgSender()), address(this).balance);
    }

    /// @dev Pays the token to the recipient
    /// @param token The token to pay
    /// @param payer The address of the payment token
    /// @param recipient The address that will receive the payment
    /// @param amount The amount to pay
    function pay(address token, address payer, address recipient, uint256 amount) internal {
        if (token == weth9 && address(this).balance >= amount) {
            // pay with WETH9
            Address.sendValue(payable(weth9), amount);
            IWETHMinimum(weth9).transfer(recipient, amount);
        } else if (payer == address(this)) SafeERC20.safeTransfer(IERC20(token), recipient, amount);
        else SafeERC20.safeTransferFrom(IERC20(token), payer, recipient, amount);
    }
}

File 19 of 23 : AbstractSelfPermit2612.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";

/// @dev Backward compatible EIP-2612 contract definitions.
//  For more information, please refer to https://eips.ethereum.org/EIPS/eip-2612#backwards-compatibility
interface IPermit2612Compatible {
    function permit(
        address holder,
        address spender,
        uint256 nonce,
        uint256 expiry,
        bool allowed,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

/// @dev Base contract for supporting the EIP-2612 specification.
/// For more information, please refer to https://eips.ethereum.org/EIPS/eip-2612
abstract contract AbstractSelfPermit2612 {
    function selfPermit(
        address token,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external payable {
        IERC20Permit(token).permit(msg.sender, address(this), value, deadline, v, r, s);
    }

    function selfPermitIfNecessary(
        address token,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external payable {
        if (IERC20(token).allowance(msg.sender, address(this)) < value)
            IERC20Permit(token).permit(msg.sender, address(this), value, deadline, v, r, s);
    }

    function selfPermitCompatible(
        address token,
        uint256 nonce,
        uint256 expiry,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external payable {
        IPermit2612Compatible(token).permit(msg.sender, address(this), nonce, expiry, true, v, r, s);
    }

    function selfPermitCompatibleIfNecessary(
        address token,
        uint256 nonce,
        uint256 expiry,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external payable {
        if (IERC20(token).allowance(msg.sender, address(this)) < type(uint256).max)
            IPermit2612Compatible(token).permit(msg.sender, address(this), nonce, expiry, true, v, r, s);
    }
}

File 20 of 23 : IMakerOrderManager.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import "@gridexprotocol/core/contracts/interfaces/callback/IGridPlaceMakerOrderCallback.sol";
import "@gridexprotocol/core/contracts/interfaces/IGridParameters.sol";

/// @title The interface for the maker order manager
interface IMakerOrderManager is IGridPlaceMakerOrderCallback {
    struct InitializeParameters {
        address tokenA;
        address tokenB;
        int24 resolution;
        uint160 priceX96;
        address recipient;
        IGridParameters.BoundaryLowerWithAmountParameters[] orders0;
        IGridParameters.BoundaryLowerWithAmountParameters[] orders1;
    }

    struct PlaceOrderParameters {
        uint256 deadline;
        address recipient;
        address tokenA;
        address tokenB;
        int24 resolution;
        bool zero;
        int24 boundaryLower;
        uint128 amount;
    }

    struct PlaceOrderInBatchParameters {
        uint256 deadline;
        address recipient;
        address tokenA;
        address tokenB;
        int24 resolution;
        bool zero;
        IGridParameters.BoundaryLowerWithAmountParameters[] orders;
    }

    /// @notice Initializes the grid with the given parameters
    function initialize(InitializeParameters calldata initializeParameters) external payable;

    /// @notice Creates the grid and initializes the grid with the given parameters
    function createGridAndInitialize(InitializeParameters calldata initializeParameters) external payable;

    /// @notice Places a maker order on the grid
    /// @return orderId The unique identifier of the order
    function placeMakerOrder(PlaceOrderParameters calldata parameters) external payable returns (uint256 orderId);

    /// @notice Places maker orders on the grid
    /// @return orderIds The unique identifiers of the orders
    function placeMakerOrderInBatch(
        PlaceOrderInBatchParameters calldata parameters
    ) external payable returns (uint256[] memory orderIds);
}

File 21 of 23 : IPayments.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

interface IPayments {
    /// @notice Unwraps the contract's WETH9 balance and sends it to recipient as ETH.
    /// @dev The amountMinimum parameter prevents malicious contracts from stealing WETH9 from users.
    /// @param amountMinimum The minimum amount of WETH9 to unwrap
    /// @param recipient The address receiving ETH
    function unwrapWETH9(uint256 amountMinimum, address recipient) external payable;

    /// @notice Refunds any native token(e.g. ETH) balance held by this contract to the `msg.sender`
    /// @dev This method is suitable for the following 2 scenarios:
    /// 1. When using exactInput, the inputted Ether is not fully consumed due to insufficient liquidity so,
    ///    remaining Ether can be withdrawn through this method
    /// 2. When using exactOutput, the inputted Ether is not fully consumed because the slippage settings
    /// are too high, henceforth, the remaining Ether can be withdrawn through this method
    function refundNativeToken() external payable;

    /// @notice Transfers the full amount of a token held by this contract to a recipient
    /// @dev The amountMinimum parameter prevents malicious contracts from stealing the token from users
    /// @param token The contract address of the tokens which will be transferred to the `recipient`
    /// @param amountMinimum The minimum amount of tokens required for a transfer
    /// @param recipient The destination address of the tokens
    function sweepToken(address token, uint256 amountMinimum, address recipient) external payable;
}

File 22 of 23 : IRelativeOrderManager.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

/// @title The interface for the relative order manager
interface IRelativeOrderManager {
    struct RelativeOrderParameters {
        uint256 deadline;
        address recipient;
        address tokenA;
        address tokenB;
        int24 resolution;
        bool zero;
        uint128 amount;
        /// @dev The price delta is the price difference between the order price and the grid price, as a Q64.96.
        /// Positive values mean the order price is higher than the grid price, and negative values mean the order price is
        /// lower than the grid price.
        int160 priceDeltaX96;
        /// @dev The minimum price of the order, as a Q64.96.
        uint160 priceMinimumX96;
        /// @dev The maximum price of the order, as a Q64.96.
        uint160 priceMaximumX96;
    }

    /// @notice Places a relative order
    /// @param parameters The parameters for the relative order
    /// @return orderId The unique identifier of the order
    function placeRelativeOrder(RelativeOrderParameters calldata parameters) external payable returns (uint256 orderId);
}

File 23 of 23 : Multicall.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/Address.sol";

abstract contract Multicall {
    function multicall(bytes[] calldata data) external payable virtual returns (bytes[] memory results) {
        results = new bytes[](data.length);
        unchecked {
            for (uint256 i = 0; i < data.length; i++) {
                results[i] = _functionDelegateCall(data[i]);
            }
        }

        return results;
    }

    function _functionDelegateCall(bytes memory data) private returns (bytes memory) {
        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = address(this).delegatecall(data);
        // M_LDCF: low-level delegate call failed
        return Address.verifyCallResult(success, returndata, "M_LDCF");
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_gridFactory","type":"address"},{"internalType":"address","name":"_weth9","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"components":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"int24","name":"resolution","type":"int24"},{"internalType":"uint160","name":"priceX96","type":"uint160"},{"internalType":"address","name":"recipient","type":"address"},{"components":[{"internalType":"int24","name":"boundaryLower","type":"int24"},{"internalType":"uint128","name":"amount","type":"uint128"}],"internalType":"struct IGridParameters.BoundaryLowerWithAmountParameters[]","name":"orders0","type":"tuple[]"},{"components":[{"internalType":"int24","name":"boundaryLower","type":"int24"},{"internalType":"uint128","name":"amount","type":"uint128"}],"internalType":"struct IGridParameters.BoundaryLowerWithAmountParameters[]","name":"orders1","type":"tuple[]"}],"internalType":"struct IMakerOrderManager.InitializeParameters","name":"parameters","type":"tuple"}],"name":"createGridAndInitialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"gridFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"gridexPlaceMakerOrderCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"int24","name":"resolution","type":"int24"},{"internalType":"uint160","name":"priceX96","type":"uint160"},{"internalType":"address","name":"recipient","type":"address"},{"components":[{"internalType":"int24","name":"boundaryLower","type":"int24"},{"internalType":"uint128","name":"amount","type":"uint128"}],"internalType":"struct IGridParameters.BoundaryLowerWithAmountParameters[]","name":"orders0","type":"tuple[]"},{"components":[{"internalType":"int24","name":"boundaryLower","type":"int24"},{"internalType":"uint128","name":"amount","type":"uint128"}],"internalType":"struct IGridParameters.BoundaryLowerWithAmountParameters[]","name":"orders1","type":"tuple[]"}],"internalType":"struct IMakerOrderManager.InitializeParameters","name":"parameters","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"int24","name":"resolution","type":"int24"},{"internalType":"bool","name":"zero","type":"bool"},{"internalType":"int24","name":"boundaryLower","type":"int24"},{"internalType":"uint128","name":"amount","type":"uint128"}],"internalType":"struct IMakerOrderManager.PlaceOrderParameters","name":"parameters","type":"tuple"}],"name":"placeMakerOrder","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"int24","name":"resolution","type":"int24"},{"internalType":"bool","name":"zero","type":"bool"},{"components":[{"internalType":"int24","name":"boundaryLower","type":"int24"},{"internalType":"uint128","name":"amount","type":"uint128"}],"internalType":"struct IGridParameters.BoundaryLowerWithAmountParameters[]","name":"orders","type":"tuple[]"}],"internalType":"struct IMakerOrderManager.PlaceOrderInBatchParameters","name":"parameters","type":"tuple"}],"name":"placeMakerOrderInBatch","outputs":[{"internalType":"uint256[]","name":"orderIds","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"int24","name":"resolution","type":"int24"},{"internalType":"bool","name":"zero","type":"bool"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"int160","name":"priceDeltaX96","type":"int160"},{"internalType":"uint160","name":"priceMinimumX96","type":"uint160"},{"internalType":"uint160","name":"priceMaximumX96","type":"uint160"}],"internalType":"struct IRelativeOrderManager.RelativeOrderParameters","name":"parameters","type":"tuple"}],"name":"placeRelativeOrder","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"refundNativeToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitCompatible","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitCompatibleIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"weth9","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c06040523480156200001157600080fd5b5060405162003b4138038062003b41833981016040819052620000349162000119565b81816200004c82620000ed60201b62001b251760201c565b620000865760405162461bcd60e51b815260206004820152600560248201526441505f4e4360d81b60448201526064015b60405180910390fd5b6200009c81620000ed60201b62001b251760201c565b620000d25760405162461bcd60e51b815260206004820152600560248201526441505f4e4360d81b60448201526064016200007d565b6001600160a01b039182166080521660a05250620001519050565b6001600160a01b03163b151590565b80516001600160a01b03811681146200011457600080fd5b919050565b600080604083850312156200012d57600080fd5b6200013883620000fc565b91506200014860208401620000fc565b90509250929050565b60805160a051613977620001ca6000396000818160ff0152818161028c01528181610c6901528181610d9901528181611ff90152818161205c01526120cd0152600081816101b9015281816103860152818161082601528181610b8401528181610f7e0152818161107101526114a501526139776000f3fe6080604052600436106100f75760003560e01c80637400b0f01161008a578063c23e3b3811610059578063c23e3b3814610321578063c2e3140a14610334578063df2ab5bb14610347578063f3995c671461035a57600080fd5b80637400b0f0146102ae5780638f61c9f7146102c1578063a6fcb341146102e1578063ac9650d81461030157600080fd5b806341865270116100c6578063418652701461023e57806342d95cc71461024657806349404b7c1461026757806350879c1c1461027a57600080fd5b806303a7dcdc146101a757806311ba05dd146102055780631872c5a2146102185780632d87f41b1461022b57600080fd5b366101a257337f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16146101a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f41505f574554483900000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b005b600080fd5b3480156101b357600080fd5b506101db7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101a0610213366004612d35565b61036d565b6101a0610226366004612d8f565b610730565b6101a0610239366004612d35565b6107eb565b6101a0610ac6565b610259610254366004612df1565b610ad8565b6040519081526020016101fc565b6101a0610275366004612e04565b610c38565b34801561028657600080fd5b506101db7f000000000000000000000000000000000000000000000000000000000000000081565b6101a06102bc366004612d8f565b610e19565b3480156102cd57600080fd5b506101a06102dc366004612e34565b610f69565b6102f46102ef366004612d35565b610fe5565b6040516101fc9190612eb4565b61031461030f366004612ef8565b6112a4565b6040516101fc9190612fe3565b61025961032f366004613063565b61138e565b6101a0610342366004612d8f565b61185d565b6101a0610355366004613076565b611985565b6101a0610368366004612d8f565b611aa8565b600073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016632ca275c06103b860208501856130b8565b6103c860408601602087016130b8565b6103d860608701604088016130e4565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff938416600482015292909116602483015260020b6044820152606401602060405180830381600087803b15801561044f57600080fd5b505af1158015610463573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104879190613101565b905060008061049c60a08501608086016130b8565b73ffffffffffffffffffffffffffffffffffffffff16146104cc576104c760a08401608085016130b8565b6104ce565b335b90508173ffffffffffffffffffffffffffffffffffffffff1663f8421a31604051806080016040528086606001602081019061050a91906130b8565b73ffffffffffffffffffffffffffffffffffffffff90811682528516602082015260400161053b60a088018861311e565b808060200260200160405190810160405280939291908181526020016000905b8282101561058757610578604083028601368190038101906131e1565b8152602001906001019061055b565b505050918352505060200161059f60c088018861311e565b808060200260200160405190810160405280939291908181526020016000905b828210156105eb576105dc604083028601368190038101906131e1565b815260200190600101906105bf565b505050919092525050604080518082019091528061063461060f60208a018a6130b8565b61061f60408b0160208c016130b8565b61062f60608c0160408d016130e4565b611b41565b81526020013373ffffffffffffffffffffffffffffffffffffffff908116909152604080518351805184166020808401919091528181015185168385015292015160020b606082015292015116608082015260a0016040516020818303038152906040526040518363ffffffff1660e01b81526004016106b5929190613299565b600060405180830381600087803b1580156106cf57600080fd5b505af11580156106e3573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261072991908101906133e9565b5050505050565b6040517f8fcbaf0c00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101869052606481018590526001608482015260ff841660a482015260c4810183905260e4810182905273ffffffffffffffffffffffffffffffffffffffff871690638fcbaf0c90610104015b600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b50505050505050505050565b600061081d6107fd60208401846130b8565b61080d60408501602086016130b8565b61062f60608601604087016130e4565b9050600061084b7f000000000000000000000000000000000000000000000000000000000000000083611bea565b905060008061086060a08601608087016130b8565b73ffffffffffffffffffffffffffffffffffffffff16146108905761088b60a08501608086016130b8565b610892565b335b90508173ffffffffffffffffffffffffffffffffffffffff1663f8421a3160405180608001604052808760600160208101906108ce91906130b8565b73ffffffffffffffffffffffffffffffffffffffff9081168252851660208201526040016108ff60a089018961311e565b808060200260200160405190810160405280939291908181526020016000905b8282101561094b5761093c604083028601368190038101906131e1565b8152602001906001019061091f565b505050918352505060200161096360c089018961311e565b808060200260200160405190810160405280939291908181526020016000905b828210156109af576109a0604083028601368190038101906131e1565b81526020019060010190610983565b505050505081525060405180604001604052808781526020016109cf3390565b73ffffffffffffffffffffffffffffffffffffffff908116909152604080518351805184166020808401919091528181015185168385015292015160020b606082015292015116608082015260a0016040516020818303038152906040526040518363ffffffff1660e01b8152600401610a4a929190613299565b600060405180830381600087803b158015610a6457600080fd5b505af1158015610a78573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610abe91908101906133e9565b505050505050565b4715610ad657610ad63347611cb5565b565b6000813542811015610b46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f41505f54544f00000000000000000000000000000000000000000000000000006044820152606401610197565b6000610b7b610b5b60608601604087016130b8565b610b6b60808701606088016130b8565b61062f60a08801608089016130e4565b90506000610ba97f000000000000000000000000000000000000000000000000000000000000000083611bea565b9050600080610bbe60408801602089016130b8565b73ffffffffffffffffffffffffffffffffffffffff1614610bee57610be960408701602088016130b8565b610bf0565b335b9050610c2e828483610c0860c08b0160a08c0161345b565b610c1860e08c0160c08d016130e4565b610c296101008d0160e08e01613478565b611e0f565b9695505050505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b158015610cc057600080fd5b505afa158015610cd4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf89190613493565b905082811015610d64576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f41505f49574554483900000000000000000000000000000000000000000000006044820152606401610197565b8015610e14576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015610df257600080fd5b505af1158015610e06573d6000803e3d6000fd5b50505050610e148282611cb5565b505050565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523360048201523060248201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9073ffffffffffffffffffffffffffffffffffffffff88169063dd62ed3e9060440160206040518083038186803b158015610ea657600080fd5b505afa158015610eba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ede9190613493565b1015610abe576040517f8fcbaf0c00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101869052606481018590526001608482015260ff841660a482015260c4810183905260e4810182905273ffffffffffffffffffffffffffffffffffffffff871690638fcbaf0c90610104016107b1565b6000610f77828401846134ac565b9050610fa77f00000000000000000000000000000000000000000000000000000000000000008260000151611f6b565b8415610fc1578051516020820151610fc191903388611ff7565b8315610729576107298160000151602001518260200151610fdf3390565b87611ff7565b6060813542811015611053576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f41505f54544f00000000000000000000000000000000000000000000000000006044820152606401610197565b6000611068610b5b60608601604087016130b8565b905060006110967f000000000000000000000000000000000000000000000000000000000000000083611bea565b90506000806110ab60408801602089016130b8565b73ffffffffffffffffffffffffffffffffffffffff16146110db576110d660408701602088016130b8565b6110dd565b335b90508173ffffffffffffffffffffffffffffffffffffffff1663b703179d60405180606001604052808473ffffffffffffffffffffffffffffffffffffffff1681526020018960a0016020810190611135919061345b565b1515815260200161114960c08b018b61311e565b808060200260200160405190810160405280939291908181526020016000905b8282101561119557611186604083028601368190038101906131e1565b81526020019060010190611169565b505050505081525060405180604001604052808781526020016111b53390565b73ffffffffffffffffffffffffffffffffffffffff908116909152604080518351805184166020808401919091528181015185168385015292015160020b606082015292015116608082015260a0016040516020818303038152906040526040518363ffffffff1660e01b8152600401611230929190613572565b600060405180830381600087803b15801561124a57600080fd5b505af115801561125e573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610c2e91908101906135ce565b60608167ffffffffffffffff8111156112bf576112bf61318d565b6040519080825280602002602001820160405280156112f257816020015b60608152602001906001900390816112dd5790505b50905060005b828110156113865761136184848381811061131557611315613603565b90506020028101906113279190613632565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061218992505050565b82828151811061137357611373613603565b60209081029190910101526001016112f8565b505b92915050565b60008135428110156113fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f41505f54544f00000000000000000000000000000000000000000000000000006044820152606401610197565b600061140e60e0850160c08601613478565b6fffffffffffffffffffffffffffffffff1611611487576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f4d4f4d5f41495a000000000000000000000000000000000000000000000000006044820152606401610197565b600061149c610b5b60608601604087016130b8565b905060006114ca7f000000000000000000000000000000000000000000000000000000000000000083611bea565b905060008173ffffffffffffffffffffffffffffffffffffffff16633850c7bd6040518163ffffffff1660e01b815260040160806040518083038186803b15801561151457600080fd5b505afa158015611528573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154c9190613697565b50505090506000808760e001602081019061156791906136ff565b60130b1361159857611580610100880160e089016136ff565b61158990613751565b6115939083613790565b6115b3565b6115a9610100880160e089016136ff565b6115b390836137c5565b90506115be81612240565b611624576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f4d4f4d5f504f52000000000000000000000000000000000000000000000000006044820152606401610197565b611636610120880161010089016130b8565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16101580156116ae575061167e610140880161012089016130b8565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1611155b611714576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f4d4f4d5f504f52000000000000000000000000000000000000000000000000006044820152606401610197565b600061174f61173a6117258461229a565b61173560a08c0160808d016130e4565b6125a3565b61174a60a08b0160808c016130e4565b6125db565b905061176160c0890160a08a0161345b565b6117df57600061177082612632565b90508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146117ab57816117db565b6117db6117be60a08b0160808c016130e4565b6117c890846137fd565b92508261174a60a08c0160808d016130e4565b9150505b6000806117f260408b0160208c016130b8565b73ffffffffffffffffffffffffffffffffffffffff16146118225761181d60408a0160208b016130b8565b611824565b335b905061185085878361183c60c08e0160a08f0161345b565b868e60c0016020810190610c299190613478565b9998505050505050505050565b6040517fdd62ed3e000000000000000000000000000000000000000000000000000000008152336004820152306024820152859073ffffffffffffffffffffffffffffffffffffffff88169063dd62ed3e9060440160206040518083038186803b1580156118ca57600080fd5b505afa1580156118de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119029190613493565b1015610abe576040517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018690526064810185905260ff8416608482015260a4810183905260c4810182905273ffffffffffffffffffffffffffffffffffffffff87169063d505accf9060e4016107b1565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8516906370a082319060240160206040518083038186803b1580156119ed57600080fd5b505afa158015611a01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a259190613493565b905082811015611a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f41505f49544b4e000000000000000000000000000000000000000000000000006044820152606401610197565b8015611aa257611aa2848383612939565b50505050565b6040517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018690526064810185905260ff8416608482015260a4810183905260c4810182905273ffffffffffffffffffffffffffffffffffffffff87169063d505accf9060e4016107b1565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b60408051606081018252600080825260208201819052918101919091528273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161115611b96579192915b60405180606001604052808573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018360020b81525090505b9392505050565b6000816020015173ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff1610611c2c57600080fd5b8151602080840151604080860151815173ffffffffffffffffffffffffffffffffffffffff95861694810194909452939091169082015260029190910b6060820152611be390608001604051602081830303815290604052805190602001207f884a6891a166f885bf6f0a3b330a25e41d1761a5aa091110a229d9a0e34b2c3660001b85612a0d565b80471015611d1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610197565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611d79576040519150601f19603f3d011682016040523d82523d6000602084013e611d7e565b606091505b5050905080610e14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610197565b60008673ffffffffffffffffffffffffffffffffffffffff1663dd5f8a7b60405180608001604052808873ffffffffffffffffffffffffffffffffffffffff16815260200187151581526020018660020b8152602001856fffffffffffffffffffffffffffffffff1681525060405180604001604052808a8152602001611e933390565b73ffffffffffffffffffffffffffffffffffffffff908116909152604080518351805184166020808401919091528181015185168385015292015160020b606082015292015116608082015260a0016040516020818303038152906040526040518363ffffffff1660e01b8152600401611f0e929190613861565b602060405180830381600087803b158015611f2857600080fd5b505af1158015611f3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f609190613493565b979650505050505050565b33611f768383611bea565b73ffffffffffffffffffffffffffffffffffffffff1614611ff3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600560248201527f43565f49430000000000000000000000000000000000000000000000000000006044820152606401610197565b5050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480156120525750804710155b1561214f576120817f000000000000000000000000000000000000000000000000000000000000000082611cb5565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b15801561211157600080fd5b505af1158015612125573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061214991906138c6565b50611aa2565b73ffffffffffffffffffffffffffffffffffffffff831630141561217d57612178848383612939565b611aa2565b611aa284848484612a37565b60606000803073ffffffffffffffffffffffffffffffffffffffff16846040516121b391906138e3565b600060405180830381855af49150503d80600081146121ee576040519150601f19603f3d011682016040523d82523d6000602084013e6121f3565b606091505b509150915061223882826040518060400160405280600681526020017f4d5f4c4443460000000000000000000000000000000000000000000000000000815250612a95565b949350505050565b6000620f188273ffffffffffffffffffffffffffffffffffffffff831610801590611388575073fff6fbe64b68d618d47c209fe40b0d8ee6e23c9173ffffffffffffffffffffffffffffffffffffffff8316111592915050565b600077ffffffffffffffffffffffffffffffffffffffff00000000602083901b166fffffffffffffffffffffffffffffffff811160071b81811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c60ff8111600390811b91821c600f811160021b90811c918211600190811b92831c9790881196179094179092171790911717176080811061234657607f810383901c9150612350565b80607f0383901b91505b908002607f81811c60ff83811c9190911c800280831c81831c1c800280841c81841c1c800280851c81851c1c800280861c81861c1c800280871c81871c1c800280881c81881c1c800280891c81891c1c8002808a1c818a1c1c8002808b1c818b1c1c8002808c1c818c1c1c8002808d1c818d1c1c8002808e1c9c81901c9c909c1c80029c8d901c9e9d7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808f0160401b60c09190911c678000000000000000161760c19b909b1c674000000000000000169a909a1760c29990991c672000000000000000169890981760c39790971c671000000000000000169690961760c49590951c670800000000000000169490941760c59390931c670400000000000000169290921760c69190911c670200000000000000161760c79190911c670100000000000000161760c89190911c6680000000000000161760c99190911c6640000000000000161760ca9190911c6620000000000000161760cb9190911c6610000000000000161760cc9190911c6608000000000000161760cd9190911c66040000000000001617691b13d180eb882abba64281027ffffffffffffffffffffffffffffffffffeb84dbf2a407dd93f221832f996e78b8101608090811d906fd9e63e52eeeb7828cf1af18004b842588301901d600281810b9083900b14612597578873ffffffffffffffffffffffffffffffffffffffff1661256f82612632565b73ffffffffffffffffffffffffffffffffffffffff1611156125915781611850565b80611850565b50979650505050505050565b60008160020b828360020b8560020b816125bf576125bf6138ff565b070160020b816125d1576125d16138ff565b0790920392915050565b60007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f3d8600284900b12156126125750818101611388565b6206c4f383830160020b131561262b5750808203611388565b5081611388565b60008060008360020b1261264b578262ffffff16612653565b8260020b6000035b905060006001821661267657700100000000000000000000000000000000612688565b6ffff97272373d413259a46990580e213a5b70ffffffffffffffffffffffffffffffffff16905060028216156126bc576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b60048216156126db576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b60088216156126fa576fffcb9843d60f6159c9db58835c9266440260801c5b6010821615612719576fff973b41fa98c081472e6896dfb254c00260801c5b6020821615612738576fff2ea16466c96a3843ec78b326b528610260801c5b6040821615612757576ffe5dee046a99a2a811c461f1969c30530260801c5b6080821615612776576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b610100821615612796576ff987a7253ac413176f2b074cf7815e540260801c5b6102008216156127b6576ff3392b0822b70005940c7a398e4b70f30260801c5b6104008216156127d6576fe7159475a2c29b7443b29c7fa6e889d90260801c5b6108008216156127f6576fd097f3bdfd2022b8845ad8f792aa58250260801c5b611000821615612816576fa9f746462d870fdf8a65dc1f90e061e50260801c5b612000821615612836576f70d869a156d2a1b890bb3df62baf32f70260801c5b614000821615612856576f31be135f97d08fd981231505542fcfa60260801c5b618000821615612876576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b62010000821615612896576e5d6af8dedb81196699c329225ee6040260801c5b620200008216156128b5576d2216e584f5fa1ea926041bedfe980260801c5b620400008216156128d2576b048a170391f7dc42444e8fa20260801c5b620800008216156128ea5766149b34ee7ac2630260801c5b60008460020b131561292957807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81612925576129256138ff565b0490505b63ffffffff0160201c9392505050565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610e149084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612aae565b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052611aa29085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161298b565b60608315612aa4575081611be3565b611be38383612bba565b6000612b10826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612bfe9092919063ffffffff16565b805190915015610e145780806020019051810190612b2e91906138c6565b610e14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610197565b815115612bca5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610197919061392e565b60606122388484600085856000808673ffffffffffffffffffffffffffffffffffffffff168587604051612c3291906138e3565b60006040518083038185875af1925050503d8060008114612c6f576040519150601f19603f3d011682016040523d82523d6000602084013e612c74565b606091505b5091509150611f608783838760608315612d13578251612d0c5773ffffffffffffffffffffffffffffffffffffffff85163b612d0c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610197565b5081612238565b6122388383612bba565b600060e08284031215612d2f57600080fd5b50919050565b600060208284031215612d4757600080fd5b813567ffffffffffffffff811115612d5e57600080fd5b61223884828501612d1d565b73ffffffffffffffffffffffffffffffffffffffff81168114612d8c57600080fd5b50565b60008060008060008060c08789031215612da857600080fd5b8635612db381612d6a565b95506020870135945060408701359350606087013560ff81168114612dd757600080fd5b9598949750929560808101359460a0909101359350915050565b60006101008284031215612d2f57600080fd5b60008060408385031215612e1757600080fd5b823591506020830135612e2981612d6a565b809150509250929050565b60008060008060608587031215612e4a57600080fd5b8435935060208501359250604085013567ffffffffffffffff80821115612e7057600080fd5b818701915087601f830112612e8457600080fd5b813581811115612e9357600080fd5b886020828501011115612ea557600080fd5b95989497505060200194505050565b6020808252825182820181905260009190848201906040850190845b81811015612eec57835183529284019291840191600101612ed0565b50909695505050505050565b60008060208385031215612f0b57600080fd5b823567ffffffffffffffff80821115612f2357600080fd5b818501915085601f830112612f3757600080fd5b813581811115612f4657600080fd5b8660208260051b8501011115612f5b57600080fd5b60209290920196919550909350505050565b60005b83811015612f88578181015183820152602001612f70565b83811115611aa25750506000910152565b60008151808452612fb1816020860160208601612f6d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613056577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613044858351612f99565b9450928501929085019060010161300a565b5092979650505050505050565b60006101408284031215612d2f57600080fd5b60008060006060848603121561308b57600080fd5b833561309681612d6a565b92506020840135915060408401356130ad81612d6a565b809150509250925092565b6000602082840312156130ca57600080fd5b8135611be381612d6a565b8060020b8114612d8c57600080fd5b6000602082840312156130f657600080fd5b8135611be3816130d5565b60006020828403121561311357600080fd5b8151611be381612d6a565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261315357600080fd5b83018035915067ffffffffffffffff82111561316e57600080fd5b6020019150600681901b360382131561318657600080fd5b9250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b80356fffffffffffffffffffffffffffffffff811681146131dc57600080fd5b919050565b6000604082840312156131f357600080fd5b6040516040810181811067ffffffffffffffff821117156132165761321661318d565b6040528235613224816130d5565b8152613232602084016131bc565b60208201529392505050565b600081518084526020808501945080840160005b8381101561328e578151805160020b88528301516fffffffffffffffffffffffffffffffff168388015260409096019590820190600101613252565b509495945050505050565b60408152600073ffffffffffffffffffffffffffffffffffffffff8085511660408401528060208601511660608401525060408401516080808401526132e260c084018261323e565b905060608501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08483030160a085015261331d828261323e565b91505082810360208401526133328185612f99565b95945050505050565b600082601f83011261334c57600080fd5b8151602067ffffffffffffffff808311156133695761336961318d565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811084821117156133ac576133ac61318d565b6040529384528581018301938381019250878511156133ca57600080fd5b83870191505b84821015611f60578151835291830191908301906133d0565b600080604083850312156133fc57600080fd5b825167ffffffffffffffff8082111561341457600080fd5b6134208683870161333b565b9350602085015191508082111561343657600080fd5b506134438582860161333b565b9150509250929050565b8015158114612d8c57600080fd5b60006020828403121561346d57600080fd5b8135611be38161344d565b60006020828403121561348a57600080fd5b611be3826131bc565b6000602082840312156134a557600080fd5b5051919050565b600081830360808112156134bf57600080fd5b6040516040810167ffffffffffffffff82821081831117156134e3576134e361318d565b8160405260608412156134f557600080fd5b60a083019350818410818511171561350f5761350f61318d565b50826040528435925061352183612d6a565b91825260208401359161353383612d6a565b82606083015260408501359250613549836130d5565b826080830152808252506060840135915061356382612d6a565b60208101919091529392505050565b6040815273ffffffffffffffffffffffffffffffffffffffff835116604082015260208301511515606082015260006040840151606060808401526135ba60a084018261323e565b905082810360208401526133328185612f99565b6000602082840312156135e057600080fd5b815167ffffffffffffffff8111156135f757600080fd5b6122388482850161333b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261366757600080fd5b83018035915067ffffffffffffffff82111561368257600080fd5b60200191503681900382131561318657600080fd5b600080600080608085870312156136ad57600080fd5b84516136b881612d6a565b60208601519094506136c9816130d5565b604086015190935063ffffffff811681146136e357600080fd5b60608601519092506136f48161344d565b939692955090935050565b60006020828403121561371157600080fd5b81358060130b8114611be357600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008160130b7fffffffffffffffffffffffff800000000000000000000000000000000000000081141561378757613787613722565b60000392915050565b600073ffffffffffffffffffffffffffffffffffffffff838116908316818110156137bd576137bd613722565b039392505050565b600073ffffffffffffffffffffffffffffffffffffffff8083168185168083038211156137f4576137f4613722565b01949350505050565b60008160020b8360020b60008112817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000000183128115161561384057613840613722565b81627fffff01831381161561385757613857613722565b5090039392505050565b73ffffffffffffffffffffffffffffffffffffffff8351168152602083015115156020820152604083015160020b60408201526fffffffffffffffffffffffffffffffff606084015116606082015260a06080820152600061223860a0830184612f99565b6000602082840312156138d857600080fd5b8151611be38161344d565b600082516138f5818460208701612f6d565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b602081526000611be36020830184612f9956fea26469706673582212208158b6338f80e190fddfec90db31f325496320168245428bb4fa775dfccca36464736f6c6343000809003300000000000000000000000032d1f0dce675902f89d72251db4ab1d728efa19c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

Deployed Bytecode

0x6080604052600436106100f75760003560e01c80637400b0f01161008a578063c23e3b3811610059578063c23e3b3814610321578063c2e3140a14610334578063df2ab5bb14610347578063f3995c671461035a57600080fd5b80637400b0f0146102ae5780638f61c9f7146102c1578063a6fcb341146102e1578063ac9650d81461030157600080fd5b806341865270116100c6578063418652701461023e57806342d95cc71461024657806349404b7c1461026757806350879c1c1461027a57600080fd5b806303a7dcdc146101a757806311ba05dd146102055780631872c5a2146102185780632d87f41b1461022b57600080fd5b366101a257337f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16146101a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f41505f574554483900000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b005b600080fd5b3480156101b357600080fd5b506101db7f00000000000000000000000032d1f0dce675902f89d72251db4ab1d728efa19c81565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101a0610213366004612d35565b61036d565b6101a0610226366004612d8f565b610730565b6101a0610239366004612d35565b6107eb565b6101a0610ac6565b610259610254366004612df1565b610ad8565b6040519081526020016101fc565b6101a0610275366004612e04565b610c38565b34801561028657600080fd5b506101db7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6101a06102bc366004612d8f565b610e19565b3480156102cd57600080fd5b506101a06102dc366004612e34565b610f69565b6102f46102ef366004612d35565b610fe5565b6040516101fc9190612eb4565b61031461030f366004612ef8565b6112a4565b6040516101fc9190612fe3565b61025961032f366004613063565b61138e565b6101a0610342366004612d8f565b61185d565b6101a0610355366004613076565b611985565b6101a0610368366004612d8f565b611aa8565b600073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000032d1f0dce675902f89d72251db4ab1d728efa19c16632ca275c06103b860208501856130b8565b6103c860408601602087016130b8565b6103d860608701604088016130e4565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff938416600482015292909116602483015260020b6044820152606401602060405180830381600087803b15801561044f57600080fd5b505af1158015610463573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104879190613101565b905060008061049c60a08501608086016130b8565b73ffffffffffffffffffffffffffffffffffffffff16146104cc576104c760a08401608085016130b8565b6104ce565b335b90508173ffffffffffffffffffffffffffffffffffffffff1663f8421a31604051806080016040528086606001602081019061050a91906130b8565b73ffffffffffffffffffffffffffffffffffffffff90811682528516602082015260400161053b60a088018861311e565b808060200260200160405190810160405280939291908181526020016000905b8282101561058757610578604083028601368190038101906131e1565b8152602001906001019061055b565b505050918352505060200161059f60c088018861311e565b808060200260200160405190810160405280939291908181526020016000905b828210156105eb576105dc604083028601368190038101906131e1565b815260200190600101906105bf565b505050919092525050604080518082019091528061063461060f60208a018a6130b8565b61061f60408b0160208c016130b8565b61062f60608c0160408d016130e4565b611b41565b81526020013373ffffffffffffffffffffffffffffffffffffffff908116909152604080518351805184166020808401919091528181015185168385015292015160020b606082015292015116608082015260a0016040516020818303038152906040526040518363ffffffff1660e01b81526004016106b5929190613299565b600060405180830381600087803b1580156106cf57600080fd5b505af11580156106e3573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261072991908101906133e9565b5050505050565b6040517f8fcbaf0c00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101869052606481018590526001608482015260ff841660a482015260c4810183905260e4810182905273ffffffffffffffffffffffffffffffffffffffff871690638fcbaf0c90610104015b600060405180830381600087803b1580156107cb57600080fd5b505af11580156107df573d6000803e3d6000fd5b50505050505050505050565b600061081d6107fd60208401846130b8565b61080d60408501602086016130b8565b61062f60608601604087016130e4565b9050600061084b7f00000000000000000000000032d1f0dce675902f89d72251db4ab1d728efa19c83611bea565b905060008061086060a08601608087016130b8565b73ffffffffffffffffffffffffffffffffffffffff16146108905761088b60a08501608086016130b8565b610892565b335b90508173ffffffffffffffffffffffffffffffffffffffff1663f8421a3160405180608001604052808760600160208101906108ce91906130b8565b73ffffffffffffffffffffffffffffffffffffffff9081168252851660208201526040016108ff60a089018961311e565b808060200260200160405190810160405280939291908181526020016000905b8282101561094b5761093c604083028601368190038101906131e1565b8152602001906001019061091f565b505050918352505060200161096360c089018961311e565b808060200260200160405190810160405280939291908181526020016000905b828210156109af576109a0604083028601368190038101906131e1565b81526020019060010190610983565b505050505081525060405180604001604052808781526020016109cf3390565b73ffffffffffffffffffffffffffffffffffffffff908116909152604080518351805184166020808401919091528181015185168385015292015160020b606082015292015116608082015260a0016040516020818303038152906040526040518363ffffffff1660e01b8152600401610a4a929190613299565b600060405180830381600087803b158015610a6457600080fd5b505af1158015610a78573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610abe91908101906133e9565b505050505050565b4715610ad657610ad63347611cb5565b565b6000813542811015610b46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f41505f54544f00000000000000000000000000000000000000000000000000006044820152606401610197565b6000610b7b610b5b60608601604087016130b8565b610b6b60808701606088016130b8565b61062f60a08801608089016130e4565b90506000610ba97f00000000000000000000000032d1f0dce675902f89d72251db4ab1d728efa19c83611bea565b9050600080610bbe60408801602089016130b8565b73ffffffffffffffffffffffffffffffffffffffff1614610bee57610be960408701602088016130b8565b610bf0565b335b9050610c2e828483610c0860c08b0160a08c0161345b565b610c1860e08c0160c08d016130e4565b610c296101008d0160e08e01613478565b611e0f565b9695505050505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b158015610cc057600080fd5b505afa158015610cd4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf89190613493565b905082811015610d64576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f41505f49574554483900000000000000000000000000000000000000000000006044820152606401610197565b8015610e14576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015610df257600080fd5b505af1158015610e06573d6000803e3d6000fd5b50505050610e148282611cb5565b505050565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523360048201523060248201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9073ffffffffffffffffffffffffffffffffffffffff88169063dd62ed3e9060440160206040518083038186803b158015610ea657600080fd5b505afa158015610eba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ede9190613493565b1015610abe576040517f8fcbaf0c00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101869052606481018590526001608482015260ff841660a482015260c4810183905260e4810182905273ffffffffffffffffffffffffffffffffffffffff871690638fcbaf0c90610104016107b1565b6000610f77828401846134ac565b9050610fa77f00000000000000000000000032d1f0dce675902f89d72251db4ab1d728efa19c8260000151611f6b565b8415610fc1578051516020820151610fc191903388611ff7565b8315610729576107298160000151602001518260200151610fdf3390565b87611ff7565b6060813542811015611053576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f41505f54544f00000000000000000000000000000000000000000000000000006044820152606401610197565b6000611068610b5b60608601604087016130b8565b905060006110967f00000000000000000000000032d1f0dce675902f89d72251db4ab1d728efa19c83611bea565b90506000806110ab60408801602089016130b8565b73ffffffffffffffffffffffffffffffffffffffff16146110db576110d660408701602088016130b8565b6110dd565b335b90508173ffffffffffffffffffffffffffffffffffffffff1663b703179d60405180606001604052808473ffffffffffffffffffffffffffffffffffffffff1681526020018960a0016020810190611135919061345b565b1515815260200161114960c08b018b61311e565b808060200260200160405190810160405280939291908181526020016000905b8282101561119557611186604083028601368190038101906131e1565b81526020019060010190611169565b505050505081525060405180604001604052808781526020016111b53390565b73ffffffffffffffffffffffffffffffffffffffff908116909152604080518351805184166020808401919091528181015185168385015292015160020b606082015292015116608082015260a0016040516020818303038152906040526040518363ffffffff1660e01b8152600401611230929190613572565b600060405180830381600087803b15801561124a57600080fd5b505af115801561125e573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610c2e91908101906135ce565b60608167ffffffffffffffff8111156112bf576112bf61318d565b6040519080825280602002602001820160405280156112f257816020015b60608152602001906001900390816112dd5790505b50905060005b828110156113865761136184848381811061131557611315613603565b90506020028101906113279190613632565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061218992505050565b82828151811061137357611373613603565b60209081029190910101526001016112f8565b505b92915050565b60008135428110156113fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f41505f54544f00000000000000000000000000000000000000000000000000006044820152606401610197565b600061140e60e0850160c08601613478565b6fffffffffffffffffffffffffffffffff1611611487576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f4d4f4d5f41495a000000000000000000000000000000000000000000000000006044820152606401610197565b600061149c610b5b60608601604087016130b8565b905060006114ca7f00000000000000000000000032d1f0dce675902f89d72251db4ab1d728efa19c83611bea565b905060008173ffffffffffffffffffffffffffffffffffffffff16633850c7bd6040518163ffffffff1660e01b815260040160806040518083038186803b15801561151457600080fd5b505afa158015611528573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154c9190613697565b50505090506000808760e001602081019061156791906136ff565b60130b1361159857611580610100880160e089016136ff565b61158990613751565b6115939083613790565b6115b3565b6115a9610100880160e089016136ff565b6115b390836137c5565b90506115be81612240565b611624576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f4d4f4d5f504f52000000000000000000000000000000000000000000000000006044820152606401610197565b611636610120880161010089016130b8565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16101580156116ae575061167e610140880161012089016130b8565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1611155b611714576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f4d4f4d5f504f52000000000000000000000000000000000000000000000000006044820152606401610197565b600061174f61173a6117258461229a565b61173560a08c0160808d016130e4565b6125a3565b61174a60a08b0160808c016130e4565b6125db565b905061176160c0890160a08a0161345b565b6117df57600061177082612632565b90508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146117ab57816117db565b6117db6117be60a08b0160808c016130e4565b6117c890846137fd565b92508261174a60a08c0160808d016130e4565b9150505b6000806117f260408b0160208c016130b8565b73ffffffffffffffffffffffffffffffffffffffff16146118225761181d60408a0160208b016130b8565b611824565b335b905061185085878361183c60c08e0160a08f0161345b565b868e60c0016020810190610c299190613478565b9998505050505050505050565b6040517fdd62ed3e000000000000000000000000000000000000000000000000000000008152336004820152306024820152859073ffffffffffffffffffffffffffffffffffffffff88169063dd62ed3e9060440160206040518083038186803b1580156118ca57600080fd5b505afa1580156118de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119029190613493565b1015610abe576040517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018690526064810185905260ff8416608482015260a4810183905260c4810182905273ffffffffffffffffffffffffffffffffffffffff87169063d505accf9060e4016107b1565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8516906370a082319060240160206040518083038186803b1580156119ed57600080fd5b505afa158015611a01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a259190613493565b905082811015611a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f41505f49544b4e000000000000000000000000000000000000000000000000006044820152606401610197565b8015611aa257611aa2848383612939565b50505050565b6040517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018690526064810185905260ff8416608482015260a4810183905260c4810182905273ffffffffffffffffffffffffffffffffffffffff87169063d505accf9060e4016107b1565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b60408051606081018252600080825260208201819052918101919091528273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161115611b96579192915b60405180606001604052808573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018360020b81525090505b9392505050565b6000816020015173ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff1610611c2c57600080fd5b8151602080840151604080860151815173ffffffffffffffffffffffffffffffffffffffff95861694810194909452939091169082015260029190910b6060820152611be390608001604051602081830303815290604052805190602001207f884a6891a166f885bf6f0a3b330a25e41d1761a5aa091110a229d9a0e34b2c3660001b85612a0d565b80471015611d1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610197565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611d79576040519150601f19603f3d011682016040523d82523d6000602084013e611d7e565b606091505b5050905080610e14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610197565b60008673ffffffffffffffffffffffffffffffffffffffff1663dd5f8a7b60405180608001604052808873ffffffffffffffffffffffffffffffffffffffff16815260200187151581526020018660020b8152602001856fffffffffffffffffffffffffffffffff1681525060405180604001604052808a8152602001611e933390565b73ffffffffffffffffffffffffffffffffffffffff908116909152604080518351805184166020808401919091528181015185168385015292015160020b606082015292015116608082015260a0016040516020818303038152906040526040518363ffffffff1660e01b8152600401611f0e929190613861565b602060405180830381600087803b158015611f2857600080fd5b505af1158015611f3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f609190613493565b979650505050505050565b33611f768383611bea565b73ffffffffffffffffffffffffffffffffffffffff1614611ff3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600560248201527f43565f49430000000000000000000000000000000000000000000000000000006044820152606401610197565b5050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480156120525750804710155b1561214f576120817f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc282611cb5565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2169063a9059cbb90604401602060405180830381600087803b15801561211157600080fd5b505af1158015612125573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061214991906138c6565b50611aa2565b73ffffffffffffffffffffffffffffffffffffffff831630141561217d57612178848383612939565b611aa2565b611aa284848484612a37565b60606000803073ffffffffffffffffffffffffffffffffffffffff16846040516121b391906138e3565b600060405180830381855af49150503d80600081146121ee576040519150601f19603f3d011682016040523d82523d6000602084013e6121f3565b606091505b509150915061223882826040518060400160405280600681526020017f4d5f4c4443460000000000000000000000000000000000000000000000000000815250612a95565b949350505050565b6000620f188273ffffffffffffffffffffffffffffffffffffffff831610801590611388575073fff6fbe64b68d618d47c209fe40b0d8ee6e23c9173ffffffffffffffffffffffffffffffffffffffff8316111592915050565b600077ffffffffffffffffffffffffffffffffffffffff00000000602083901b166fffffffffffffffffffffffffffffffff811160071b81811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c60ff8111600390811b91821c600f811160021b90811c918211600190811b92831c9790881196179094179092171790911717176080811061234657607f810383901c9150612350565b80607f0383901b91505b908002607f81811c60ff83811c9190911c800280831c81831c1c800280841c81841c1c800280851c81851c1c800280861c81861c1c800280871c81871c1c800280881c81881c1c800280891c81891c1c8002808a1c818a1c1c8002808b1c818b1c1c8002808c1c818c1c1c8002808d1c818d1c1c8002808e1c9c81901c9c909c1c80029c8d901c9e9d7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808f0160401b60c09190911c678000000000000000161760c19b909b1c674000000000000000169a909a1760c29990991c672000000000000000169890981760c39790971c671000000000000000169690961760c49590951c670800000000000000169490941760c59390931c670400000000000000169290921760c69190911c670200000000000000161760c79190911c670100000000000000161760c89190911c6680000000000000161760c99190911c6640000000000000161760ca9190911c6620000000000000161760cb9190911c6610000000000000161760cc9190911c6608000000000000161760cd9190911c66040000000000001617691b13d180eb882abba64281027ffffffffffffffffffffffffffffffffffeb84dbf2a407dd93f221832f996e78b8101608090811d906fd9e63e52eeeb7828cf1af18004b842588301901d600281810b9083900b14612597578873ffffffffffffffffffffffffffffffffffffffff1661256f82612632565b73ffffffffffffffffffffffffffffffffffffffff1611156125915781611850565b80611850565b50979650505050505050565b60008160020b828360020b8560020b816125bf576125bf6138ff565b070160020b816125d1576125d16138ff565b0790920392915050565b60007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f3d8600284900b12156126125750818101611388565b6206c4f383830160020b131561262b5750808203611388565b5081611388565b60008060008360020b1261264b578262ffffff16612653565b8260020b6000035b905060006001821661267657700100000000000000000000000000000000612688565b6ffff97272373d413259a46990580e213a5b70ffffffffffffffffffffffffffffffffff16905060028216156126bc576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b60048216156126db576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b60088216156126fa576fffcb9843d60f6159c9db58835c9266440260801c5b6010821615612719576fff973b41fa98c081472e6896dfb254c00260801c5b6020821615612738576fff2ea16466c96a3843ec78b326b528610260801c5b6040821615612757576ffe5dee046a99a2a811c461f1969c30530260801c5b6080821615612776576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b610100821615612796576ff987a7253ac413176f2b074cf7815e540260801c5b6102008216156127b6576ff3392b0822b70005940c7a398e4b70f30260801c5b6104008216156127d6576fe7159475a2c29b7443b29c7fa6e889d90260801c5b6108008216156127f6576fd097f3bdfd2022b8845ad8f792aa58250260801c5b611000821615612816576fa9f746462d870fdf8a65dc1f90e061e50260801c5b612000821615612836576f70d869a156d2a1b890bb3df62baf32f70260801c5b614000821615612856576f31be135f97d08fd981231505542fcfa60260801c5b618000821615612876576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b62010000821615612896576e5d6af8dedb81196699c329225ee6040260801c5b620200008216156128b5576d2216e584f5fa1ea926041bedfe980260801c5b620400008216156128d2576b048a170391f7dc42444e8fa20260801c5b620800008216156128ea5766149b34ee7ac2630260801c5b60008460020b131561292957807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81612925576129256138ff565b0490505b63ffffffff0160201c9392505050565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610e149084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612aae565b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052611aa29085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161298b565b60608315612aa4575081611be3565b611be38383612bba565b6000612b10826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612bfe9092919063ffffffff16565b805190915015610e145780806020019051810190612b2e91906138c6565b610e14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610197565b815115612bca5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610197919061392e565b60606122388484600085856000808673ffffffffffffffffffffffffffffffffffffffff168587604051612c3291906138e3565b60006040518083038185875af1925050503d8060008114612c6f576040519150601f19603f3d011682016040523d82523d6000602084013e612c74565b606091505b5091509150611f608783838760608315612d13578251612d0c5773ffffffffffffffffffffffffffffffffffffffff85163b612d0c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610197565b5081612238565b6122388383612bba565b600060e08284031215612d2f57600080fd5b50919050565b600060208284031215612d4757600080fd5b813567ffffffffffffffff811115612d5e57600080fd5b61223884828501612d1d565b73ffffffffffffffffffffffffffffffffffffffff81168114612d8c57600080fd5b50565b60008060008060008060c08789031215612da857600080fd5b8635612db381612d6a565b95506020870135945060408701359350606087013560ff81168114612dd757600080fd5b9598949750929560808101359460a0909101359350915050565b60006101008284031215612d2f57600080fd5b60008060408385031215612e1757600080fd5b823591506020830135612e2981612d6a565b809150509250929050565b60008060008060608587031215612e4a57600080fd5b8435935060208501359250604085013567ffffffffffffffff80821115612e7057600080fd5b818701915087601f830112612e8457600080fd5b813581811115612e9357600080fd5b886020828501011115612ea557600080fd5b95989497505060200194505050565b6020808252825182820181905260009190848201906040850190845b81811015612eec57835183529284019291840191600101612ed0565b50909695505050505050565b60008060208385031215612f0b57600080fd5b823567ffffffffffffffff80821115612f2357600080fd5b818501915085601f830112612f3757600080fd5b813581811115612f4657600080fd5b8660208260051b8501011115612f5b57600080fd5b60209290920196919550909350505050565b60005b83811015612f88578181015183820152602001612f70565b83811115611aa25750506000910152565b60008151808452612fb1816020860160208601612f6d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613056577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613044858351612f99565b9450928501929085019060010161300a565b5092979650505050505050565b60006101408284031215612d2f57600080fd5b60008060006060848603121561308b57600080fd5b833561309681612d6a565b92506020840135915060408401356130ad81612d6a565b809150509250925092565b6000602082840312156130ca57600080fd5b8135611be381612d6a565b8060020b8114612d8c57600080fd5b6000602082840312156130f657600080fd5b8135611be3816130d5565b60006020828403121561311357600080fd5b8151611be381612d6a565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261315357600080fd5b83018035915067ffffffffffffffff82111561316e57600080fd5b6020019150600681901b360382131561318657600080fd5b9250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b80356fffffffffffffffffffffffffffffffff811681146131dc57600080fd5b919050565b6000604082840312156131f357600080fd5b6040516040810181811067ffffffffffffffff821117156132165761321661318d565b6040528235613224816130d5565b8152613232602084016131bc565b60208201529392505050565b600081518084526020808501945080840160005b8381101561328e578151805160020b88528301516fffffffffffffffffffffffffffffffff168388015260409096019590820190600101613252565b509495945050505050565b60408152600073ffffffffffffffffffffffffffffffffffffffff8085511660408401528060208601511660608401525060408401516080808401526132e260c084018261323e565b905060608501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08483030160a085015261331d828261323e565b91505082810360208401526133328185612f99565b95945050505050565b600082601f83011261334c57600080fd5b8151602067ffffffffffffffff808311156133695761336961318d565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811084821117156133ac576133ac61318d565b6040529384528581018301938381019250878511156133ca57600080fd5b83870191505b84821015611f60578151835291830191908301906133d0565b600080604083850312156133fc57600080fd5b825167ffffffffffffffff8082111561341457600080fd5b6134208683870161333b565b9350602085015191508082111561343657600080fd5b506134438582860161333b565b9150509250929050565b8015158114612d8c57600080fd5b60006020828403121561346d57600080fd5b8135611be38161344d565b60006020828403121561348a57600080fd5b611be3826131bc565b6000602082840312156134a557600080fd5b5051919050565b600081830360808112156134bf57600080fd5b6040516040810167ffffffffffffffff82821081831117156134e3576134e361318d565b8160405260608412156134f557600080fd5b60a083019350818410818511171561350f5761350f61318d565b50826040528435925061352183612d6a565b91825260208401359161353383612d6a565b82606083015260408501359250613549836130d5565b826080830152808252506060840135915061356382612d6a565b60208101919091529392505050565b6040815273ffffffffffffffffffffffffffffffffffffffff835116604082015260208301511515606082015260006040840151606060808401526135ba60a084018261323e565b905082810360208401526133328185612f99565b6000602082840312156135e057600080fd5b815167ffffffffffffffff8111156135f757600080fd5b6122388482850161333b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261366757600080fd5b83018035915067ffffffffffffffff82111561368257600080fd5b60200191503681900382131561318657600080fd5b600080600080608085870312156136ad57600080fd5b84516136b881612d6a565b60208601519094506136c9816130d5565b604086015190935063ffffffff811681146136e357600080fd5b60608601519092506136f48161344d565b939692955090935050565b60006020828403121561371157600080fd5b81358060130b8114611be357600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008160130b7fffffffffffffffffffffffff800000000000000000000000000000000000000081141561378757613787613722565b60000392915050565b600073ffffffffffffffffffffffffffffffffffffffff838116908316818110156137bd576137bd613722565b039392505050565b600073ffffffffffffffffffffffffffffffffffffffff8083168185168083038211156137f4576137f4613722565b01949350505050565b60008160020b8360020b60008112817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000000183128115161561384057613840613722565b81627fffff01831381161561385757613857613722565b5090039392505050565b73ffffffffffffffffffffffffffffffffffffffff8351168152602083015115156020820152604083015160020b60408201526fffffffffffffffffffffffffffffffff606084015116606082015260a06080820152600061223860a0830184612f99565b6000602082840312156138d857600080fd5b8151611be38161344d565b600082516138f5818460208701612f6d565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b602081526000611be36020830184612f9956fea26469706673582212208158b6338f80e190fddfec90db31f325496320168245428bb4fa775dfccca36464736f6c63430008090033

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

00000000000000000000000032d1f0dce675902f89d72251db4ab1d728efa19c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

-----Decoded View---------------
Arg [0] : _gridFactory (address): 0x32d1F0Dce675902f89D72251DB4AB1d728efa19c
Arg [1] : _weth9 (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000032d1f0dce675902f89d72251db4ab1d728efa19c
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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