ETH Price: $2,391.29 (-8.92%)

Contract

0x33a5A405B97C6e77f3cA07a55FeF08454F5550bd

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
0x001800014141845902025-12-25 0:44:0238 days ago1766623442IN
0x33a5A405...54F5550bd
0 ETH0.000001480.069096
0x001800014141845372025-12-25 0:43:4938 days ago1766623429IN
0x33a5A405...54F5550bd
0 ETH0.000001450.067619
0x001800014141775512025-12-25 0:14:5338 days ago1766621693IN
0x33a5A405...54F5550bd
0 ETH0.000000890.04173
0x001800014141646062025-12-24 23:21:0438 days ago1766618464IN
0x33a5A405...54F5550bd
0 ETH0.000000670.031469
0x001800014141634442025-12-24 23:16:1438 days ago1766618174IN
0x33a5A405...54F5550bd
0 ETH0.000000650.030313
0x010001004025679292025-11-21 11:10:4972 days ago1763723449IN
0x33a5A405...54F5550bd
0 ETH0.000000680.0308
0x010001004025663952025-11-21 11:04:2772 days ago1763723067IN
0x33a5A405...54F5550bd
0 ETH0.000000450.018961
0x010001004025663822025-11-21 11:04:2372 days ago1763723063IN
0x33a5A405...54F5550bd
0 ETH0.000000460.019253
0x010001004025654042025-11-21 11:00:2072 days ago1763722820IN
0x33a5A405...54F5550bd
0 ETH0.000000440.017756
0x010001004025653932025-11-21 11:00:1772 days ago1763722817IN
0x33a5A405...54F5550bd
0 ETH0.000000440.018047
0x010001004025647642025-11-21 10:57:4072 days ago1763722660IN
0x33a5A405...54F5550bd
0 ETH0.000000610.025849
0x010001004025647502025-11-21 10:57:3672 days ago1763722656IN
0x33a5A405...54F5550bd
0 ETH0.00000060.025617
0x010001004025624582025-11-21 10:48:0672 days ago1763722086IN
0x33a5A405...54F5550bd
0 ETH0.000000910.036459
0x010001004025624512025-11-21 10:48:0472 days ago1763722084IN
0x33a5A405...54F5550bd
0 ETH0.000000920.037019
0x010001004025621672025-11-21 10:46:5372 days ago1763722013IN
0x33a5A405...54F5550bd
0 ETH0.000000870.034691
0x010001004025621602025-11-21 10:46:5172 days ago1763722011IN
0x33a5A405...54F5550bd
0 ETH0.000000870.03461
0x010001004025620532025-11-21 10:46:2572 days ago1763721985IN
0x33a5A405...54F5550bd
0 ETH0.000000890.035635
0x010001004025620462025-11-21 10:46:2372 days ago1763721983IN
0x33a5A405...54F5550bd
0 ETH0.000000880.035173
0x010001004025617772025-11-21 10:45:1672 days ago1763721916IN
0x33a5A405...54F5550bd
0 ETH0.000001010.04136
0x010001004025617702025-11-21 10:45:1472 days ago1763721914IN
0x33a5A405...54F5550bd
0 ETH0.000001010.041483
0x010001004025614312025-11-21 10:43:4972 days ago1763721829IN
0x33a5A405...54F5550bd
0 ETH0.000001220.051038
0x010001004025614172025-11-21 10:43:4772 days ago1763721827IN
0x33a5A405...54F5550bd
0 ETH0.000001250.051646
0x010001004025612972025-11-21 10:43:1772 days ago1763721797IN
0x33a5A405...54F5550bd
0 ETH0.000001340.055629
0x010001004025612902025-11-21 10:43:1572 days ago1763721795IN
0x33a5A405...54F5550bd
0 ETH0.000001350.056321
0x010001004025610082025-11-21 10:42:0472 days ago1763721724IN
0x33a5A405...54F5550bd
0 ETH0.000001620.068597
View all transactions

Latest 1 internal transaction

Parent Transaction Hash Block From To
1396831622023-10-11 13:48:28843 days ago1697032108  Contract Creation0 ETH

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
OrderBook

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 4150 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.18;

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";

import "./interfaces/IOrderBook.sol";
import "./interfaces/ILighterV2FlashCallback.sol";
import "./interfaces/ILighterV2TransferCallback.sol";

import "./libraries/LinkedList.sol";
import "./libraries/Errors.sol";
import {IERC20Minimal} from "./interfaces/external/IERC20Minimal.sol";

/**
 * @title Order Book
 * @notice Contract representing an order book for trading token pairs. It manages
 * the creation and interaction of orders, and tracks various parameters related
 * to order management.
 * @notice OrderBook can handle different types of orders and order-life-cycle management
 * @notice User can swap tokens in the order book via direct call on orderBook or via router
 * @dev for direct order book interaction of order-creation and token-swap, ensure the caller
 *      has implemented the callback interface to handle payments
 */
contract OrderBook is IOrderBook, ReentrancyGuard {
    /// @dev Limits the value for size and price ticks
    uint8 public constant LOG10_TICK_THRESHOLD = 38;

    /// @dev Limits the total number of orders that can be created
    uint32 public constant ORDER_ID_THRESHOLD = (1 << 32) - 1;

    /// @dev Limits the unique number of creators, which are smart contracts
    /// that call the order book and implements the callback interfaces
    uint32 public constant CREATOR_ID_THRESHOLD = (1 << 31) - 1;

    uint64 public constant MAX_PRICE = type(uint64).max;

    // Using the LinkedListLib for order management
    using LinkedListLib for LinkedList;

    /// @notice The ERC20 token used as token0 in the trading pair
    IERC20Minimal public immutable token0;

    /// @notice The ERC20 token used as token1 in the trading pair
    IERC20Minimal public immutable token1;

    /// @notice The id of the order book
    uint8 public immutable orderBookId;

    /// @notice The minimum base token0 amount required for an order to be valid
    uint64 public immutable minToken0BaseAmount;

    /// @notice The minimum base token1 amount required for an order to be valid (token0Base * priceBase)
    uint128 public immutable minToken1BaseAmount;

    /// @notice The step size for token0 amounts
    uint128 public immutable sizeTick;

    /// @notice The step size for unit token0 price
    uint128 public immutable priceTick;

    /// @notice The multiplier used for calculating the amount1 from priceBase and amount0Base
    uint128 public immutable priceMultiplier;

    /// @notice The divider used for calculating the amount1 from priceBase and amount0Base
    uint128 public immutable priceDivider;

    /// @dev The id of the next order to be created, also used for setting ownerId and creatorId for gas efficiency
    uint32 public orderIdCounter;

    /// @notice The data structure used for storing the active orders
    /// @dev If an ask order, book needs to store at least amount0Base * sizeTick amount of token0. If a bid order,
    /// book needs to store at least amount0Base * priceMultiplier * sizeTick / priceDivider amount of token1
    LinkedList private _orders;

    /// @notice Mapping from address to claimable token0 balance
    mapping(address => uint256) public claimableToken0Balance;

    /// @notice Mapping from address to claimable token1 balance
    mapping(address => uint256) public claimableToken1Balance;

    /// @notice Mapping from ownerId to address
    mapping(uint32 => address) public ownerIdToAddress;

    /// @notice Mapping from address to ownerId
    mapping(address => uint32) public addressToOwnerId;

    /// @notice Mapping from address to creatorId
    mapping(address => uint32) public addressToCreatorId;

    /// @notice Mapping from creatorId to address
    mapping(uint32 => address) public creatorIdToAddress;

    /// @notice A struct containing variables used for order matching.
    struct MatchOrderLocalVars {
        uint32 index; // id of the maker order being matched
        address makerAddress; // owner address of the maker order
        uint256 filledAmount0; // Amount of token0 already filled in the taker order
        uint256 filledAmount1; // Amount of token1 already filled in the taker order
        uint256 amount; // Exact amount of tokens to be sent or received in a swap
        uint64 makerAmount0BaseChange; // Maker order amont0Base change
        uint256 swapAmount0; // Amount of token0 to be swaped with maker order
        uint256 swapAmount1; // Amount of token1 to be swaped with maker order
        uint64 swapAmount0Base; // Base amount of token0 to be swaped with maker order
        uint128 swapAmount1Base; // Base amount of token1 to be swaped with maker order
        bool atLeastOneFullSwap; // Flag indicating if taker took at least one maker order fully
        bool fullTakerFill; // Flag indicating if taker order is fully filled
        uint32 swapCount; // Count of swaps performed
        uint32 swapCapacity; // Capacity swaps array
        SwapData[] swaps; // Array of swap data
    }

    /// @notice A struct containing payment-related data for order and swap operations.
    struct PaymentData {
        bool isAsk; // Flag indicating if the taker order is an ask order
        bool isPerfMode; // Flag indicating if the taker order is a performance limit order
        address recipient; // Recipient address for payments
        uint256 filledAmount0; // Total amount of token0 in the swaps
        uint256 filledAmount1; // Total amount of token1 in the swaps
        uint256 remainingLimitOrderAmount; // Amount taker needs to pay for unmatched part of their limit order
        uint32 swapCount; // Count of swaps performed
        SwapData[] swaps; // Array of swap data
        bytes callbackData; // Additional callback data for payment.
    }

    /// @dev Struct that holds swap data during matching
    struct SwapData {
        address makerAddress; // Address of the owner of the matched order
        uint256 swapAmount; // Amount of tokens matched in the order
        bool isPerfMode; // Flag indicating if the order is in performance mode
    }

    /// @notice Contract constructor
    /// @param _orderBookId The id of the order book
    /// @param _token0Address The base token address
    /// @param _token1Address The quote token address
    /// @param _logSizeTick log10 of base token tick, size of the base token
    /// should be multiples of 10**logSizeTick for limit orders
    /// @param _logPriceTick log10 of price tick, price of unit base token
    /// should be multiples of 10**logPriceTick for limit orders
    /// @param _minToken0BaseAmount minimum token0Base amount for limit orders
    /// @param _minToken1BaseAmount minimum token1Base amount (token0Base * priceBase) for limit orders
    /// @dev Initializes the contract and linked lists with provided parameters
    constructor(
        uint8 _orderBookId,
        address _token0Address,
        address _token1Address,
        uint8 _logSizeTick,
        uint8 _logPriceTick,
        uint64 _minToken0BaseAmount,
        uint128 _minToken1BaseAmount
    ) {
        token0 = IERC20Minimal(_token0Address);
        token1 = IERC20Minimal(_token1Address);
        orderBookId = _orderBookId;
        uint8 token0Decimals = token0.decimals();

        if (_logSizeTick >= LOG10_TICK_THRESHOLD || _logPriceTick >= LOG10_TICK_THRESHOLD) {
            revert Errors.LighterV2CreateOrderBook_InvalidTickCombination();
        }

        sizeTick = uint128(10 ** _logSizeTick);
        priceTick = uint128(10 ** _logPriceTick);
        uint128 priceMultiplierCheck = 1;
        uint128 priceDividerCheck = 1;
        if (_logSizeTick + _logPriceTick >= token0Decimals) {
            if (_logSizeTick + _logPriceTick - token0Decimals >= LOG10_TICK_THRESHOLD) {
                revert Errors.LighterV2CreateOrderBook_InvalidTickCombination();
            }
            priceMultiplierCheck = uint128(10 ** (_logSizeTick + _logPriceTick - token0Decimals));
        } else {
            if (token0Decimals - _logSizeTick - _logPriceTick >= LOG10_TICK_THRESHOLD) {
                revert Errors.LighterV2CreateOrderBook_InvalidTickCombination();
            }
            priceDividerCheck = uint128(10 ** (token0Decimals - _logPriceTick - _logSizeTick));
        }

        priceMultiplier = priceMultiplierCheck;
        priceDivider = priceDividerCheck;

        if (_minToken0BaseAmount == 0 || _minToken1BaseAmount == 0) {
            revert Errors.LighterV2CreateOrderBook_InvalidMinAmount();
        }
        minToken0BaseAmount = _minToken0BaseAmount;
        minToken1BaseAmount = _minToken1BaseAmount;

        // Create the head node for asks linked list, this node can not be deleted
        _orders.asks[0] = LimitOrder({
            prev: 0,
            next: 1,
            perfMode_creatorId: 0,
            ownerId: 1,
            amount0Base: 0,
            priceBase: 0
        });
        // Create the tail node for asks linked list, this node can not be deleted
        _orders.asks[1] = LimitOrder({
            prev: 0,
            next: 1,
            perfMode_creatorId: 0,
            ownerId: 1,
            amount0Base: 0,
            priceBase: MAX_PRICE
        });
        // Create the head node for bids linked list, this node can not be deleted
        _orders.bids[0] = LimitOrder({
            prev: 0,
            next: 1,
            perfMode_creatorId: 0,
            ownerId: 1,
            amount0Base: 0,
            priceBase: MAX_PRICE
        });
        // Create the tail node for bids linked list, this node can not be deleted
        _orders.bids[1] = LimitOrder({
            prev: 0,
            next: 1,
            perfMode_creatorId: 0,
            ownerId: 1,
            amount0Base: 0,
            priceBase: 0
        });
        // Id 0 and 1 are used for heads and tails. Next order should start from id 2
        orderIdCounter = 2;
    }

    /// @inheritdoc IOrderBook
    function createOrder(
        uint64 amount0Base,
        uint64 priceBase,
        bool isAsk,
        address owner,
        uint32 hintId,
        OrderType orderType,
        bytes memory callbackData
    ) external override nonReentrant returns (uint32 newOrderId) {
        newOrderId = orderIdCounter;

        // For every order type, the amount0Base needs to be at least 1
        if (amount0Base == 0) {
            revert Errors.LighterV2Order_AmountTooSmall();
        }

        // priceBase needs to be at least priceDivider
        // this guarantees that any increase of amount0Base will increase amount1 by at least 1
        // as priceDivider is guaranteed to be at least 1, an error is always thrown if priceBase = 0,
        // which is reserved for the dummy order with id 0
        if (priceBase < priceDivider) {
            revert Errors.LighterV2Order_PriceTooSmall();
        }

        // do not allow orders with the max price, as the price is reserved for the big dummy order.
        // this is required so no order is inserted after the dummy order with id 1
        if (priceBase == MAX_PRICE) {
            revert Errors.LighterV2Order_PriceTooBig();
        }

        if (orderType == OrderType.LimitOrder || orderType == OrderType.PerformanceLimitOrder) {
            if (hintId >= newOrderId) {
                revert Errors.LighterV2Order_InvalidHintId();
            }
            if ((amount0Base < minToken0BaseAmount || priceBase * amount0Base < minToken1BaseAmount)) {
                revert Errors.LighterV2Order_AmountTooSmall();
            }
        }

        LimitOrder memory newOrder;

        {
            if (newOrderId >= ORDER_ID_THRESHOLD) {
                revert Errors.LighterV2Order_OrderIdExceedsLimit();
            }

            orderIdCounter = newOrderId + 1;

            newOrder = LimitOrder({
                perfMode_creatorId: 0, // Only set if order needs to be inserted into the order book
                prev: 0, // Only set if order needs to be inserted into the order book
                next: 0, // Only set if order needs to be inserted into the order book
                ownerId: 0, // Only set if order needs to be inserted into the order book
                amount0Base: amount0Base,
                priceBase: priceBase
            });

            emit CreateOrder(owner, newOrderId, amount0Base, priceBase, isAsk, orderType);
        }

        (uint256 filledAmount0, uint256 filledAmount1, uint32 swapCount, SwapData[] memory swaps) = _matchOrder(
            newOrder,
            newOrderId,
            owner,
            isAsk
        );
        // Short circuit payments if Fill or Kill order is not fully filled and needs to be killed
        if (orderType == OrderType.FoKOrder && newOrder.amount0Base > 0) {
            revert Errors.LighterV2Order_FoKNotFilled();
        }

        // Computes the amount caller needs to pay for remaning part of their limit order
        uint256 remainingLimitOrderAmount = 0;
        if (
            (orderType == OrderType.LimitOrder || orderType == OrderType.PerformanceLimitOrder) &&
            newOrder.amount0Base > 0
        ) {
            remainingLimitOrderAmount = (isAsk)
                ? (uint256(newOrder.amount0Base) * sizeTick)
                : (uint256(newOrder.amount0Base) * newOrder.priceBase * priceMultiplier) / priceDivider;
        }

        // Handle token transfers between makers and takers and for remainingLimitOrderAmount
        if (
            filledAmount0 > 0 ||
            filledAmount1 > 0 ||
            orderType == OrderType.LimitOrder ||
            orderType == OrderType.PerformanceLimitOrder
        ) {
            _handlePayments(
                PaymentData(
                    isAsk,
                    orderType == OrderType.PerformanceLimitOrder,
                    owner,
                    filledAmount0,
                    filledAmount1,
                    remainingLimitOrderAmount,
                    swapCount,
                    swaps,
                    callbackData
                )
            );
        }

        // If the order is not fully filled, set remaining value in newOrder and insert it into respective order book
        if (remainingLimitOrderAmount > 0) {
            // Get the ownerId if exists, otherwise set the ownerId using the from address
            newOrder.ownerId = addressToOwnerId[owner];
            if (newOrder.ownerId == 0) {
                newOrder.ownerId = newOrderId;
                addressToOwnerId[owner] = newOrder.ownerId;
                ownerIdToAddress[newOrderId] = owner;
            }

            // creatorId can only be non-zero if msg.sender different from the owner and order is a limit order
            if (msg.sender != owner) {
                newOrder.perfMode_creatorId = addressToCreatorId[msg.sender];
                if (newOrder.perfMode_creatorId == 0) {
                    // LimitOrder stores 31 bits for the creator id, only allow setting a non-zero creator id if it's below the limit
                    if (newOrderId >= CREATOR_ID_THRESHOLD) {
                        revert Errors.LighterV2Order_CreatorIdExceedsLimit();
                    }
                    newOrder.perfMode_creatorId = newOrderId;
                    addressToCreatorId[msg.sender] = newOrder.perfMode_creatorId;
                    creatorIdToAddress[newOrder.perfMode_creatorId] = msg.sender;
                }
                newOrder.perfMode_creatorId <<= 1;
            }

            if (orderType == OrderType.PerformanceLimitOrder) {
                newOrder.perfMode_creatorId = newOrder.perfMode_creatorId | 1;
            }

            if (isAsk) {
                _orders.asks[newOrderId] = newOrder;
                _orders.insert(newOrderId, isAsk, hintId);
            } else {
                _orders.bids[newOrderId] = newOrder;
                _orders.insert(newOrderId, isAsk, hintId);
            }
        }
    }

    /// @inheritdoc IOrderBook
    function cancelLimitOrder(uint32 id, address owner) external override nonReentrant returns (bool) {
        if (!isOrderActive(id)) {
            return false;
        }

        LimitOrder memory order;

        bool isAsk = isAskOrder(id);
        if (isAsk) {
            order = _orders.asks[id];
        } else {
            order = _orders.bids[id];
        }

        address _owner = ownerIdToAddress[order.ownerId];
        uint32 creatorId = (order.perfMode_creatorId >> 1);
        address creator = _owner;
        if (creatorId != 0) {
            creator = creatorIdToAddress[creatorId];
        }

        // only the creator or the owner can cancel the order
        if ((owner != _owner) || (msg.sender != creator && msg.sender != _owner)) {
            revert Errors.LighterV2Owner_CallerCannotCancel();
        }

        emit CancelLimitOrder(id);

        if (isAsk) {
            uint256 amount0 = uint256(order.amount0Base) * sizeTick;
            bool success = false;
            if ((order.perfMode_creatorId & 1) == 0) {
                success = _sendToken(token0, _owner, amount0);
            }
            if (!success) {
                claimableToken0Balance[_owner] += amount0;
                if ((order.perfMode_creatorId & 1) == 0) {
                    emit ClaimableBalanceIncrease(_owner, amount0, true);
                }
            }
            _orders.erase(id, isAsk);
        } else {
            uint256 amount1 = ((uint256(order.amount0Base) * order.priceBase) * priceMultiplier) / priceDivider;
            bool success = false;
            if ((order.perfMode_creatorId & 1) == 0) {
                success = _sendToken(token1, _owner, amount1);
            }
            if (!success) {
                claimableToken1Balance[_owner] += amount1;
                if ((order.perfMode_creatorId & 1) == 0) {
                    emit ClaimableBalanceIncrease(_owner, amount1, false);
                }
            }
            _orders.erase(id, isAsk);
        }
        return true;
    }

    /// @inheritdoc IOrderBook
    function swapExactSingle(
        bool isAsk,
        bool isExactInput,
        uint256 exactAmount,
        uint256 expectedAmount,
        address recipient,
        bytes memory callbackData
    ) external override nonReentrant returns (uint256, uint256) {
        (uint256 filledAmount0, uint256 filledAmount1, uint32 swapCount, SwapData[] memory swaps) = _matchSwapOrder(
            isAsk,
            isExactInput,
            exactAmount,
            expectedAmount,
            recipient
        );

        _handlePayments(
            PaymentData(isAsk, false, recipient, filledAmount0, filledAmount1, 0, swapCount, swaps, callbackData)
        );

        emit SwapExactAmount(msg.sender, recipient, isExactInput, isAsk, filledAmount0, filledAmount1);

        return (filledAmount0, filledAmount1);
    }

    /// @inheritdoc IOrderBook
    function flashLoan(
        address recipient,
        uint256 amount0,
        uint256 amount1,
        bytes calldata callbackData
    ) external override nonReentrant {
        uint256 orderBookToken0BalanceBeforeLoan = token0.balanceOf(address(this));
        uint256 orderBookToken1BalanceBeforeLoan = token1.balanceOf(address(this));

        if (amount0 > 0 && !_sendToken(token0, recipient, amount0)) {
            revert Errors.LighterV2TokenTransfer_Failed();
        }

        if (amount1 > 0 && !_sendToken(token1, recipient, amount1)) {
            revert Errors.LighterV2TokenTransfer_Failed();
        }

        ILighterV2FlashCallback(msg.sender).flashLoanCallback(callbackData);

        if (token0.balanceOf(address(this)) < orderBookToken0BalanceBeforeLoan) {
            revert Errors.LighterV2FlashLoan_InsufficentCallbackTransfer();
        }

        if (token1.balanceOf(address(this)) < orderBookToken1BalanceBeforeLoan) {
            revert Errors.LighterV2FlashLoan_InsufficentCallbackTransfer();
        }

        emit FlashLoan(msg.sender, recipient, amount0, amount1);
    }

    /// @inheritdoc IOrderBook
    function depositToken(
        uint256 amountToDeposit,
        bool isToken0,
        bytes memory callbackData
    ) external override nonReentrant {
        address owner = msg.sender;
        IERC20Minimal token = isToken0 ? token0 : token1;
        uint256 balanceBefore = token.balanceOf(address(this));

        ILighterV2TransferCallback(owner).lighterV2TransferCallback(amountToDeposit, token, callbackData);

        if (token.balanceOf(address(this)) < balanceBefore + amountToDeposit) {
            revert Errors.LighterV2Vault_InsufficentCallbackTransfer();
        }
        if (isToken0) {
            claimableToken0Balance[owner] += amountToDeposit;
        } else {
            claimableToken1Balance[owner] += amountToDeposit;
        }
        emit ClaimableBalanceIncrease(owner, amountToDeposit, isToken0);
    }

    /// @inheritdoc IOrderBook
    function claimToken(uint256 amountToClaim, bool isToken0) external override nonReentrant {
        address owner = msg.sender;
        uint256 amount = isToken0 ? claimableToken0Balance[owner] : claimableToken1Balance[owner];
        if (amountToClaim > 0 && amountToClaim <= amount) {
            if (isToken0) {
                claimableToken0Balance[owner] -= amountToClaim;
                if (!_sendToken(token0, owner, amountToClaim)) {
                    revert Errors.LighterV2TokenTransfer_Failed();
                }
            } else {
                claimableToken1Balance[owner] -= amountToClaim;
                if (!_sendToken(token1, owner, amountToClaim)) {
                    revert Errors.LighterV2TokenTransfer_Failed();
                }
            }
            emit ClaimableBalanceDecrease(owner, amountToClaim, isToken0);
        } else {
            revert Errors.LighterV2Vault_InvalidClaimAmount();
        }
    }

    /// @dev Matches the given limit order against the available maker orders.
    /// @param order The taker order to be matched
    /// @param orderId The id of the taker order
    /// @param isAsk Indicates whether the taker order is an ask order or not
    /// @return filledAmount0 The total amount of token0 swapped in matching
    /// @return filledAmount1 The total amount of token1 swapped in matching
    /// @return swapCount The count of swaps performed
    /// @return swaps The array that contains data of swaps performed
    function _matchOrder(
        LimitOrder memory order,
        uint32 orderId,
        address owner,
        bool isAsk
    ) internal returns (uint256, uint256, uint32, SwapData[] memory) {
        MatchOrderLocalVars memory matchOrderLocalVars;

        mapping(uint32 => LimitOrder) storage makerOrders = isAsk ? _orders.bids : _orders.asks;

        matchOrderLocalVars.index = makerOrders[0].next;

        while (matchOrderLocalVars.index != 1 && order.amount0Base > 0) {
            LimitOrder storage bestOrder = makerOrders[matchOrderLocalVars.index];
            matchOrderLocalVars.makerAddress = ownerIdToAddress[bestOrder.ownerId];
            (matchOrderLocalVars.swapAmount0Base, matchOrderLocalVars.swapAmount1Base) = getLimitOrderSwapAmounts(
                order.amount0Base,
                order.priceBase,
                bestOrder.amount0Base,
                bestOrder.priceBase,
                isAsk
            );

            if (matchOrderLocalVars.swapAmount0Base == 0 || matchOrderLocalVars.swapAmount1Base == 0) break;

            matchOrderLocalVars.swapAmount0 = uint256(matchOrderLocalVars.swapAmount0Base) * sizeTick;
            matchOrderLocalVars.swapAmount1 =
                (uint256(matchOrderLocalVars.swapAmount1Base) * priceMultiplier) /
                priceDivider;

            if (isAsk) {
                emit Swap(
                    orderId,
                    matchOrderLocalVars.index,
                    owner,
                    matchOrderLocalVars.makerAddress,
                    matchOrderLocalVars.swapAmount0,
                    matchOrderLocalVars.swapAmount1
                );
            } else {
                emit Swap(
                    matchOrderLocalVars.index,
                    orderId,
                    matchOrderLocalVars.makerAddress,
                    owner,
                    matchOrderLocalVars.swapAmount0,
                    matchOrderLocalVars.swapAmount1
                );
            }

            matchOrderLocalVars.filledAmount0 = matchOrderLocalVars.filledAmount0 + matchOrderLocalVars.swapAmount0;
            matchOrderLocalVars.filledAmount1 = matchOrderLocalVars.filledAmount1 + matchOrderLocalVars.swapAmount1;

            // if there are not enough free slots in the matchOrderLocalVars.matchedOrders, increase size to accommodate
            if (matchOrderLocalVars.swapCount == matchOrderLocalVars.swapCapacity) {
                // initial capacity will be 4, and we'll double afterwards
                uint32 newCapacity = 4;
                if (matchOrderLocalVars.swapCapacity != 0) {
                    newCapacity = matchOrderLocalVars.swapCapacity * 2;
                }

                SwapData[] memory newSwaps = new SwapData[](newCapacity);
                for (uint32 i = 0; i < matchOrderLocalVars.swapCapacity; i += 1) {
                    newSwaps[i] = matchOrderLocalVars.swaps[i];
                }

                matchOrderLocalVars.swaps = newSwaps;
                matchOrderLocalVars.swapCapacity = newCapacity;
            }

            matchOrderLocalVars.swaps[matchOrderLocalVars.swapCount++] = SwapData({
                makerAddress: matchOrderLocalVars.makerAddress,
                isPerfMode: (bestOrder.perfMode_creatorId & 1 == 1),
                swapAmount: isAsk ? matchOrderLocalVars.swapAmount0 : matchOrderLocalVars.swapAmount1
            });

            order.amount0Base = order.amount0Base - matchOrderLocalVars.swapAmount0Base;

            if (bestOrder.amount0Base == matchOrderLocalVars.swapAmount0Base) {
                // Remove the best bid from the order book if it is fully filled
                matchOrderLocalVars.atLeastOneFullSwap = true;
                bestOrder.ownerId = 0;
            } else {
                // Update the best bid if it is partially filled
                bestOrder.amount0Base = bestOrder.amount0Base - matchOrderLocalVars.swapAmount0Base;
                break;
            }

            matchOrderLocalVars.index = bestOrder.next;
        }
        if (matchOrderLocalVars.atLeastOneFullSwap) {
            makerOrders[matchOrderLocalVars.index].prev = 0;
            makerOrders[0].next = matchOrderLocalVars.index;
        }

        return (
            matchOrderLocalVars.filledAmount0,
            matchOrderLocalVars.filledAmount1,
            matchOrderLocalVars.swapCount,
            matchOrderLocalVars.swaps
        );
    }

    /// @dev Matches the given swap request (market order) against the available maker orders.
    /// @param isAsk Indicates whether the swap request is an ask order or not
    /// @param isExactInput Indicates whether the swapper indicated exact input or output
    /// @param exactAmount The exact amount swapper wants to receive or send depending on isExactInput
    /// @param thresholdAmount The minimum amount to be received or maximum amount to be sent
    /// @param recipient The recipient address for swaps
    /// @return filledAmount0 The total amount of token0 swapped in matching
    /// @return filledAmount1 The total amount of token1 swapped in matching
    /// @return swapCount The count of swaps performed
    /// @return swaps The array that contains data of swaps performed
    function _matchSwapOrder(
        bool isAsk,
        bool isExactInput,
        uint256 exactAmount,
        uint256 thresholdAmount,
        address recipient
    ) internal returns (uint256, uint256, uint32, SwapData[] memory) {
        MatchOrderLocalVars memory matchOrderLocalVars;
        mapping(uint32 => LimitOrder) storage makerOrders = isAsk ? _orders.bids : _orders.asks;
        matchOrderLocalVars.amount = exactAmount;
        matchOrderLocalVars.index = makerOrders[0].next;
        matchOrderLocalVars.fullTakerFill = exactAmount == 0;

        while (matchOrderLocalVars.index != 1 && !matchOrderLocalVars.fullTakerFill) {
            LimitOrder storage bestMatch = makerOrders[matchOrderLocalVars.index];

            (
                matchOrderLocalVars.swapAmount0,
                matchOrderLocalVars.swapAmount1,
                matchOrderLocalVars.makerAmount0BaseChange,
                matchOrderLocalVars.fullTakerFill
            ) = (isExactInput && isAsk) || (!isExactInput && !isAsk)
                ? getSwapAmountsForToken0(matchOrderLocalVars.amount, isAsk, bestMatch.amount0Base, bestMatch.priceBase)
                : getSwapAmountsForToken1(
                    matchOrderLocalVars.amount,
                    isAsk,
                    bestMatch.amount0Base,
                    bestMatch.priceBase
                );

            // If the swap amount is 0, break the loop since next orders guaranteed to have 0 as well
            if (matchOrderLocalVars.swapAmount0 == 0 || matchOrderLocalVars.swapAmount1 == 0) break;

            if (isAsk) {
                emit Swap(
                    0, // emit 0 id for swap requests (market order)
                    matchOrderLocalVars.index,
                    recipient,
                    ownerIdToAddress[bestMatch.ownerId],
                    matchOrderLocalVars.swapAmount0,
                    matchOrderLocalVars.swapAmount1
                );
            } else {
                emit Swap(
                    matchOrderLocalVars.index,
                    0, // emit 0 id for swap requests (market order)
                    ownerIdToAddress[bestMatch.ownerId],
                    recipient,
                    matchOrderLocalVars.swapAmount0,
                    matchOrderLocalVars.swapAmount1
                );
            }

            matchOrderLocalVars.filledAmount0 += matchOrderLocalVars.swapAmount0;
            matchOrderLocalVars.filledAmount1 += matchOrderLocalVars.swapAmount1;

            // if there are not enough free slots in the matchOrderLocalVars.swaps, increase size to accommodate
            if (matchOrderLocalVars.swapCount == matchOrderLocalVars.swapCapacity) {
                // initial capacity will be 4, and we'll double afterwards
                uint32 newCapacity = 4;
                if (matchOrderLocalVars.swapCapacity != 0) {
                    newCapacity = matchOrderLocalVars.swapCapacity * 2;
                }

                SwapData[] memory newSwaps = new SwapData[](newCapacity);
                for (uint32 i = 0; i < matchOrderLocalVars.swapCapacity; i += 1) {
                    newSwaps[i] = matchOrderLocalVars.swaps[i];
                }

                matchOrderLocalVars.swaps = newSwaps;
                matchOrderLocalVars.swapCapacity = newCapacity;
            }

            matchOrderLocalVars.swaps[matchOrderLocalVars.swapCount++] = SwapData({
                makerAddress: ownerIdToAddress[bestMatch.ownerId],
                isPerfMode: (bestMatch.perfMode_creatorId & 1 == 1),
                swapAmount: isAsk ? matchOrderLocalVars.swapAmount0 : matchOrderLocalVars.swapAmount1
            });

            if (bestMatch.amount0Base == matchOrderLocalVars.makerAmount0BaseChange) {
                // Remove the best bid from the order book if it is fully filled
                matchOrderLocalVars.atLeastOneFullSwap = true;
                bestMatch.ownerId = 0;
            } else {
                // Update the best bid if it is partially filled
                bestMatch.amount0Base -= matchOrderLocalVars.makerAmount0BaseChange;
                break;
            }

            matchOrderLocalVars.index = bestMatch.next;
            if (matchOrderLocalVars.fullTakerFill) {
                // Break before updating the amount, if taker specifies exactOutput taker will receive largest
                // amount of output tokens they can buy with same input needed for exactOutput. Amount can be
                // negative if taker is receiving slightly more than exactOutput (depending on the ticks).
                break;
            }

            if ((isAsk && isExactInput) || (!isAsk && !isExactInput)) {
                matchOrderLocalVars.amount -= matchOrderLocalVars.swapAmount0;
            } else {
                matchOrderLocalVars.amount -= matchOrderLocalVars.swapAmount1;
            }
        }

        if (matchOrderLocalVars.atLeastOneFullSwap) {
            makerOrders[matchOrderLocalVars.index].prev = 0;
            makerOrders[0].next = matchOrderLocalVars.index;
        }

        if (!matchOrderLocalVars.fullTakerFill) {
            revert Errors.LighterV2Swap_NotEnoughLiquidity();
        }

        if (
            isExactInput &&
            ((isAsk && matchOrderLocalVars.filledAmount1 < thresholdAmount) ||
                (!isAsk && matchOrderLocalVars.filledAmount0 < thresholdAmount))
        ) {
            revert Errors.LighterV2Swap_NotEnoughOutput();
        } else if (
            !isExactInput &&
            ((isAsk && matchOrderLocalVars.filledAmount0 > thresholdAmount) ||
                (!isAsk && matchOrderLocalVars.filledAmount1 > thresholdAmount))
        ) {
            revert Errors.LighterV2Swap_TooMuchRequested();
        }

        return (
            matchOrderLocalVars.filledAmount0,
            matchOrderLocalVars.filledAmount1,
            matchOrderLocalVars.swapCount,
            matchOrderLocalVars.swaps
        );
    }

    /// @dev Handles the payment logic for a matched order.
    /// @param paymentData The payment data containing information about the swaps and payments
    function _handlePayments(PaymentData memory paymentData) internal {
        // Determine debit and credit tokens based on the order type
        IERC20Minimal debitToken = paymentData.isAsk ? token0 : token1;
        IERC20Minimal creditToken = paymentData.isAsk ? token1 : token0;

        uint256 debitTokenAmount = (paymentData.isAsk ? paymentData.filledAmount0 : paymentData.filledAmount1) +
            paymentData.remainingLimitOrderAmount;
        uint256 creditTokenAmount = paymentData.isAsk ? paymentData.filledAmount1 : paymentData.filledAmount0;

        if (creditTokenAmount > 0) {
            if (paymentData.isPerfMode) {
                if (paymentData.isAsk) {
                    claimableToken1Balance[paymentData.recipient] += creditTokenAmount;
                } else {
                    claimableToken0Balance[paymentData.recipient] += creditTokenAmount;
                }
                // Omit emitting ClaimableBalanceIncrease for gas savings, can be inferred from swap events
            } else {
                if (!_sendToken(creditToken, paymentData.recipient, creditTokenAmount)) {
                    revert Errors.LighterV2TokenTransfer_Failed();
                }
            }
        }

        if (paymentData.isPerfMode) {
            if (paymentData.isAsk) {
                if (claimableToken0Balance[msg.sender] < debitTokenAmount) {
                    revert Errors.LighterV2Order_InsufficientClaimableBalance();
                }
                claimableToken0Balance[msg.sender] -= debitTokenAmount;
            } else {
                if (claimableToken1Balance[msg.sender] < debitTokenAmount) {
                    revert Errors.LighterV2Order_InsufficientClaimableBalance();
                }
                claimableToken1Balance[msg.sender] -= debitTokenAmount;
            }
            // Omit emitting ClaimableBalanceDecrease for gas savings, can be inferred from swap and order creation events
        } else {
            uint256 debitTokenBalanceBeforeDebit = debitToken.balanceOf(address(this));

            ILighterV2TransferCallback(msg.sender).lighterV2TransferCallback(
                debitTokenAmount,
                debitToken,
                paymentData.callbackData
            );

            if (debitToken.balanceOf(address(this)) < (debitTokenBalanceBeforeDebit + debitTokenAmount)) {
                revert Errors.LighterV2Order_InsufficentCallbackTransfer();
            }
        }

        // Loop through swaps and transfer tokens to the maker order owners
        for (uint32 swapIndex; swapIndex < paymentData.swapCount; ++swapIndex) {
            SwapData memory swapData = paymentData.swaps[swapIndex];
            if (swapData.isPerfMode) {
                if (paymentData.isAsk) {
                    claimableToken0Balance[swapData.makerAddress] += swapData.swapAmount;
                } else {
                    claimableToken1Balance[swapData.makerAddress] += swapData.swapAmount;
                }
                // omit emitting ClaimableBalanceIncrease for gas savings, can be inferred from swap events
            } else {
                bool success = _sendToken(debitToken, swapData.makerAddress, swapData.swapAmount);
                if (!success) {
                    // if transfer to maker fails, mark the amount as claimable for maker
                    if (paymentData.isAsk) {
                        claimableToken0Balance[swapData.makerAddress] += swapData.swapAmount;
                    } else {
                        claimableToken1Balance[swapData.makerAddress] += swapData.swapAmount;
                    }
                    emit ClaimableBalanceIncrease(swapData.makerAddress, swapData.swapAmount, paymentData.isAsk);
                }
            }
        }
    }

    /// @notice Transfer tokens from the order book to the user
    /// @param tokenToTransfer The token to transfer
    /// @param to The address to transfer to
    /// @param amount The amount to transfer
    /// @return success Whether the transfer was successful or not
    function _sendToken(IERC20Minimal tokenToTransfer, address to, uint256 amount) internal returns (bool) {
        uint256 orderBookBalanceBefore = tokenToTransfer.balanceOf(address(this));
        bool success = false;
        try tokenToTransfer.transfer(to, amount) returns (bool ret) {
            success = ret;
        } catch {
            success = false;
        }

        uint256 sentAmount = success ? amount : 0;
        if (tokenToTransfer.balanceOf(address(this)) + sentAmount < orderBookBalanceBefore) {
            revert Errors.LighterV2Base_ContractBalanceDoesNotMatchSentAmount();
        }
        return success;
    }

    /// @inheritdoc IOrderBook
    function suggestHintId(uint64 priceBase, bool isAsk) external view override returns (uint32) {
        return _orders.suggestHintId(priceBase, isAsk);
    }

    /// @inheritdoc IOrderBook
    function getLimitOrderSwapAmounts(
        uint64 takerOrderAmount0Base,
        uint64 takerOrderPriceBase,
        uint64 makerOrderAmount0Base,
        uint64 makerOrderPriceBase,
        bool isTakerAsk
    ) public pure override returns (uint64 amount0BaseReturn, uint128 amount1BaseReturn) {
        // If the takerOrder is an ask, and the makerOrder price is at least
        // the takerOrder's price, then the takerOrder can be filled
        // If the takerOrder is a bid, and the makerOrder price is at most
        // the takerOrder's price, then the takerOrder can be filled
        if (
            (isTakerAsk && makerOrderPriceBase >= takerOrderPriceBase) ||
            (!isTakerAsk && takerOrderPriceBase >= makerOrderPriceBase)
        ) {
            if (takerOrderAmount0Base < makerOrderAmount0Base) {
                amount0BaseReturn = takerOrderAmount0Base;
            } else {
                amount0BaseReturn = makerOrderAmount0Base;
            }
            return (amount0BaseReturn, uint128(amount0BaseReturn * makerOrderPriceBase));
        }

        return (0, 0);
    }

    /// @inheritdoc IOrderBook
    function getSwapAmountsForToken0(
        uint256 amount0,
        bool isAsk,
        uint64 makerAmount0Base,
        uint64 makerPriceBase
    )
        public
        view
        override
        returns (uint256 swapAmount0, uint256 swapAmount1, uint64 amount0BaseDelta, bool fullTakerFill)
    {
        uint256 amount0BaseToTake;
        if (isAsk) {
            amount0BaseToTake = amount0 / sizeTick;
        } else {
            amount0BaseToTake = Math.ceilDiv(amount0, sizeTick);
        }
        if (amount0BaseToTake > makerAmount0Base) {
            amount0BaseToTake = makerAmount0Base;
            fullTakerFill = false;
        } else {
            fullTakerFill = true;
        }
        amount0BaseDelta = uint64(amount0BaseToTake);
        swapAmount0 = uint256(amount0BaseDelta) * sizeTick;
        swapAmount1 = (uint256(amount0BaseDelta) * makerPriceBase * priceMultiplier) / priceDivider;
    }

    /// @inheritdoc IOrderBook
    function getSwapAmountsForToken1(
        uint256 amount1,
        bool isAsk,
        uint64 makerAmount0Base,
        uint64 makerPriceBase
    )
        public
        view
        override
        returns (uint256 swapAmount0, uint256 swapAmount1, uint64 amount0BaseDelta, bool fullTakerFill)
    {
        uint256 amount0BaseToTake = Math.mulDiv(amount1, priceDivider, makerPriceBase * priceMultiplier);
        if (isAsk) {
            swapAmount1 = (amount0BaseToTake * makerPriceBase * priceMultiplier) / priceDivider;
            if (swapAmount1 < amount1) {
                amount0BaseToTake += 1;
            }
        }
        if (amount0BaseToTake > makerAmount0Base) {
            amount0BaseToTake = makerAmount0Base;
            fullTakerFill = false;
        } else {
            fullTakerFill = true;
        }
        amount0BaseDelta = uint64(amount0BaseToTake);
        swapAmount1 = (uint256(amount0BaseDelta) * makerPriceBase * priceMultiplier) / priceDivider;
        swapAmount0 = uint256(amount0BaseDelta) * sizeTick;
    }

    /// @inheritdoc IOrderBook
    function getPaginatedOrders(
        uint32 startOrderId,
        bool isAsk,
        uint32 limit
    ) external view override returns (OrderQueryItem memory) {
        return _orders.getPaginatedOrders(startOrderId, isAsk, limit, ownerIdToAddress, sizeTick, priceTick);
    }

    /// @inheritdoc IOrderBook
    function getLimitOrder(bool isAsk, uint32 id) external view override returns (LimitOrder memory) {
        return isAsk ? _orders.asks[id] : _orders.bids[id];
    }

    /// @inheritdoc IOrderBook
    function isOrderActive(uint32 id) public view override returns (bool) {
        return _orders.asks[id].ownerId != 0 || _orders.bids[id].ownerId != 0;
    }

    /// @inheritdoc IOrderBook
    function isAskOrder(uint32 id) public view override returns (bool) {
        if (!isOrderActive(id)) {
            revert Errors.LighterV2Order_OrderDoesNotExist();
        }

        return _orders.asks[id].ownerId > 1;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 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 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;

/// @title Minimal ERC20 interface for lighter
/// @notice Contains a subset of the full ERC20 interface that is used in lighter
interface IERC20Minimal {
    /// @notice Returns the balance of the account provided
    /// @param account The account to get the balance of
    /// @return balance The balance of the account
    function balanceOf(address account) external view returns (uint256);

    /// @notice Transfers given amount of tokens from caller to the recipient
    /// @param recipient The recipient of the transfer
    /// @param amount The amount of the transfer
    /// @return success Returns true for a successful transfer, false for unsuccessful
    function transfer(address recipient, uint256 amount) external returns (bool);

    /// @notice Transfers given amount of tokens from the sender to the recipient
    /// @param sender The sender of the transfer
    /// @param recipient The recipient of the transfer
    /// @param amount The amount of the transfer
    /// @return success Returns true for a successful transfer, false for unsuccessful
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /// @return decimals Returns the decimals of the token
    function decimals() external returns (uint8);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.18;

/// @title Callback for IOrderBook#flashLoan
/// @notice Any contract that calls IOrderBook#flashLoan must implement this interface
interface ILighterV2FlashCallback {
    /// @notice Called from `msg.sender` after transferring flashLoan to the recipient from IOrderBook#flashLoan
    /// @dev In the implementation you must repay the pool the assets sent by flashLoan.
    /// The caller of this method must be checked to be an order book deployed by the Factory
    /// @param callbackData Data passed through by the caller via the IOrderBook#flashLoan call
    function flashLoanCallback(bytes calldata callbackData) external;
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.18;

import "./external/IERC20Minimal.sol";

/// @title Callback for IOrderBook#swapExactSingle and IOrderBook#createOrder
/// @notice Any contract that calls IOrderBook#swapExactSingle and IOrderBook#createOrder must implement this interface with one exception
/// @dev If orderType is PerformanceLimitOrder, then no need to implement this interface
/// @dev PerformanceLimitOrder handles payments with pre-deposited funds by market-makers
interface ILighterV2TransferCallback {
    /// @notice Called by order book after transferring received assets from IOrderBook#swapExactInput or IOrderBook#swapExactOutput for payments
    /// @dev In the implementation order creator must pay the order book the assets for the order
    /// The caller of this method must be checked to be an order book deployed by the Factory
    /// @param callbackData Data passed through by the caller via the IOrderBook#swapExactSingle or IOrderBook#swapExactOutput call
    function lighterV2TransferCallback(
        uint256 debitTokenAmount,
        IERC20Minimal debitToken,
        bytes calldata callbackData
    ) external;
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.18;

import "../libraries/LinkedList.sol";
import "./external/IERC20Minimal.sol";

/// @title Order Book Interface
/// @notice Order book implements spot trading endpoints and storage for two assets which conform to the IERC20Minimal specification.
interface IOrderBook {
    /// @notice Limit Order type.
    enum OrderType {
        LimitOrder, // Limit order
        PerformanceLimitOrder, // Limit order that uses claimable balances
        FoKOrder, // Fill or Kill limit order
        IoCOrder // Immediate or Cancel limit order
    }

    /// @notice Struct to use for storing limit orders
    struct LimitOrder {
        uint32 perfMode_creatorId; // lowest bit for perfMode, remaining 31 bits for creatorId
        uint32 prev; // id of the previous order in the list
        uint32 next; // id of the next order in the list
        uint32 ownerId; // id of the owner of the order
        uint64 amount0Base; // amount0Base of the order
        uint64 priceBase; // priceBase of the order
    }

    /// @notice Struct to use returning the paginated orders
    struct OrderQueryItem {
        bool isAsk; // true if the paginated orders are ask orders, false if bid orders
        uint32[] ids; // order ids of returned orders
        address[] owners; // owner addresses of returned orders
        uint256[] amount0s; // amount0s of returned orders (amount0Base * sizeTick)
        uint256[] prices; // prices of returned orders (priceBase * priceTick)
    }

    /// @notice Emitted when a limit order gets created
    /// @param owner The address of the order owner
    /// @param id The id of the order
    /// @param amount0Base The amount of token0 in the limit order in terms of number of sizeTicks
    /// @param priceBase The price of the token0 in terms of price ticks
    /// @param isAsk Whether the order is an ask order
    /// @param orderType type of the order
    event CreateOrder(
        address indexed owner,
        uint32 indexed id,
        uint64 amount0Base,
        uint64 priceBase,
        bool isAsk,
        OrderType orderType
    );

    /// @notice Emitted when a limit order gets canceled
    /// @param id The id of the canceled order
    event CancelLimitOrder(uint32 indexed id);

    /// @notice Emitted when a taker initiates a swap (market order)
    /// @param sender The address that initiated the swap
    /// @param recipient The address that received the tokens from the swap
    /// @param isExactInput Whether the input amount is exact or output amount is exact
    /// @param isAsk Whether the order is an ask order
    /// @param swapAmount0 The amount of token0 that was swapped
    /// @param swapAmount1 The amount of token1 that was swapped
    event SwapExactAmount(
        address indexed sender,
        address indexed recipient,
        bool isExactInput,
        bool isAsk,
        uint256 swapAmount0,
        uint256 swapAmount1
    );

    /// @notice Emitted when a maker gets filled by a taker
    /// @param askId The id of the ask order
    /// @param bidId The id of the bid order
    /// @param askOwner The address of the ask order owner
    /// @param bidOwner The address of the bid order owner
    /// @param amount0 The amount of token0 that was swapped
    /// @param amount1 The amount of token1 that was swapped
    event Swap(
        uint32 indexed askId,
        uint32 indexed bidId,
        address askOwner,
        address bidOwner,
        uint256 amount0,
        uint256 amount1
    );

    /// @notice Emitted when flashLoan is called
    /// @param sender The address that initiated the flashLoan, and that received the callback
    /// @param recipient The address that received the tokens from flash loan
    /// @param amount0 The amount of token0 that was flash loaned
    /// @param amount1 The amount of token1 that was flash loaned
    event FlashLoan(address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1);

    /// @notice Emitted when user claimable balance is increased due to deposit or order operations
    event ClaimableBalanceIncrease(address indexed owner, uint256 amountDelta, bool isToken0);

    /// @notice Emitted when user claimable balance is decreased due to withdraw or order operations
    event ClaimableBalanceDecrease(address indexed owner, uint256 amountDelta, bool isToken0);

    /// @notice Creates a limit order.
    /// @param amount0Base The amount of token0 in the limit order in terms of number of sizeTicks.
    /// amount0 is calculated by multiplying amount0Base by sizeTick.
    /// @param priceBase The price of the token0 in terms of price ticks.
    /// amount1 is calculated by multiplying priceBase by sizeTick and priceMultiplier and dividing by priceDivider.
    /// @param isAsk Whether the order is an ask order
    /// @param owner The address which will receive the funds and that can
    /// cancel this order. When called by a router, it'll be populated
    /// with msg.sender. Smart wallets should use msg.sender directly.
    /// @param hintId Hint on where to insert the order in the order book.
    /// Can be calculated with suggestHintId function, is not used for FoK and IoC orders.
    /// @param orderType type of the order, if FoK or IoC remaining order will not be added for future matches.
    /// @param callbackData data to be passed to callback
    /// @return id The id of the order
    function createOrder(
        uint64 amount0Base,
        uint64 priceBase,
        bool isAsk,
        address owner,
        uint32 hintId,
        OrderType orderType,
        bytes memory callbackData
    ) external returns (uint32);

    /// @notice Cancels an outstanding limit order. Refunds the remaining tokens in the order to the owner
    /// @param id The id of the order to cancel
    /// @param owner The address of the order sender
    /// @return isCanceled Whether the order was successfully canceled or not
    function cancelLimitOrder(uint32 id, address owner) external returns (bool);

    /// @notice Swaps exact input or output amount of token0 or token1 for the other token
    /// @param isAsk Whether the order is an ask order, if true sender pays token0 and receives token1
    /// @param isExactInput Whether the input amount is exact or output amount is exact
    /// @param exactAmount exact token amount to swap (can be token0 or token1 based on isAsk and isExactInput)
    /// @param expectedAmount expected token amount to receive (can be token0 or token1 based on isAsk and isExactInput).
    /// if isExactInput is true, then expectedAmount is the minimum amount to receive.
    /// if isExactInput is false, then expectedAmount is the maximum amount to pay
    /// @param recipient The address which will receive the output
    /// @param callbackData data to be passed to callback
    function swapExactSingle(
        bool isAsk,
        bool isExactInput,
        uint256 exactAmount,
        uint256 expectedAmount,
        address recipient,
        bytes memory callbackData
    ) external returns (uint256, uint256);

    /// @notice Flash loans token0 and token1 to the recipient, sender receives the callback
    /// @param recipient The address which will receive the token0 and token1
    /// @param amount0 The amount of token0 to flash loan
    /// @param amount1 The amount of token1 to flash loan
    /// @param callbackData data to be passed to callback
    function flashLoan(address recipient, uint256 amount0, uint256 amount1, bytes calldata callbackData) external;

    /// @notice Deposits token0 or token1 from user to the order book and marks it as claimable
    /// to be used for performance limit orders for gas efficient limit order creations.
    /// @param amountToDeposit Amount to deposit
    /// @param isToken0 Whether the deposit is token0 or token1
    /// @param callbackData Byte data to send to callback
    function depositToken(uint256 amountToDeposit, bool isToken0, bytes memory callbackData) external;

    /// @notice Withdraws deposited or swapped token0 or token1 to the owner.
    /// @param amountToClaim Amount to withdraw
    /// @param isToken0 Whether the claimable token is token0 or token1
    function claimToken(uint256 amountToClaim, bool isToken0) external;

    /// @notice Finds the order id where the new order should be inserted to the right of
    /// Meant to be used off-chain to find the hintId for limit order creation functions
    /// @param priceBase basePrice derived from amount0Base and amount1Base
    /// @param isAsk Whether the new order is an ask order
    /// @return hintId The id of the order where the new order
    /// should be inserted to the right of
    function suggestHintId(uint64 priceBase, bool isAsk) external view returns (uint32);

    /// @notice Returns the amount of token0 and token1 to traded between two limit orders
    /// @param takerOrderAmount0Base The amount0Base of the taker order
    /// @param takerOrderPriceBase The priceBase of the taker order
    /// @param makerOrderAmount0Base The amount0Base of the maker order
    /// @param makerOrderPriceBase The priceBase of the maker order
    /// @param isTakerAsk True if taker order is an ask
    /// @return amount0BaseReturn The amount0Base to be traded
    /// @return amount1BaseReturn The amount1Base to be traded
    function getLimitOrderSwapAmounts(
        uint64 takerOrderAmount0Base,
        uint64 takerOrderPriceBase,
        uint64 makerOrderAmount0Base,
        uint64 makerOrderPriceBase,
        bool isTakerAsk
    ) external pure returns (uint64, uint128);

    /// @notice Returns the amount of token0 and token1 to traded between maker and swapper
    /// @param amount0 Exact token0 amount taker wants to trade
    /// @param isAsk True if swapper is an ask
    /// @param makerAmount0Base The amount0Base of the maker order
    /// @param makerPriceBase The priceBase of the maker order
    /// @return swapAmount0 The amount of token0 to be swapped
    /// @return swapAmount1 The amount of token1 to be swapped
    /// @return amount0BaseDelta Maker order baseAmount0 change
    /// @return fullTakerFill True if swapper can be fully filled by maker order
    function getSwapAmountsForToken0(
        uint256 amount0,
        bool isAsk,
        uint64 makerAmount0Base,
        uint64 makerPriceBase
    ) external view returns (uint256, uint256, uint64, bool);

    /// @notice Returns the amount of token0 and token1 to traded between maker and swapper
    /// @param amount1 Exact token1 amount taker wants to trade
    /// @param isAsk True if swapper is an ask
    /// @param makerAmount0Base The amount0Base of the maker order
    /// @param makerPriceBase The priceBase of the maker order
    /// @return swapAmount0 The amount of token0 to be swapped
    /// @return swapAmount1 The amount of token1 to be swapped
    /// @return amount0BaseDelta Maker order baseAmount0 change
    /// @return fullTakerFill True if swapper can be fully filled by maker order
    function getSwapAmountsForToken1(
        uint256 amount1,
        bool isAsk,
        uint64 makerAmount0Base,
        uint64 makerPriceBase
    ) external view returns (uint256, uint256, uint64, bool);

    /// @notice Returns price sorted limit orders with pagination
    /// @param startOrderId orderId from where the pagination should start (not inclusive)
    /// @dev caller can pass 0 to start from the top of the book
    /// @param isAsk Whether to return ask or bid orders
    /// @param limit Number number of orders to return in the page
    /// @return orderData The paginated order data
    function getPaginatedOrders(
        uint32 startOrderId,
        bool isAsk,
        uint32 limit
    ) external view returns (OrderQueryItem memory orderData);

    /// @notice Returns the limit order of the given index
    /// @param isAsk Whether the order is an ask order
    /// @param id The id of the order
    /// @return order The limit order
    function getLimitOrder(bool isAsk, uint32 id) external view returns (LimitOrder memory);

    /// @notice Returns whether an order is active or not
    /// @param id The id of the order
    /// @return isActive True if the order is active, false otherwise
    function isOrderActive(uint32 id) external view returns (bool);

    /// @notice Returns whether an order is an ask order or not, fails if order is not active
    /// @param id The id of the order
    /// @return isAsk True if the order is an ask order, false otherwise
    function isAskOrder(uint32 id) external view returns (bool);

    /// @notice Returns the constant for Log value of TickThreshold
    /// @return LOG10_TICK_THRESHOLD threshold for Log value of TickThreshold
    function LOG10_TICK_THRESHOLD() external view returns (uint8);

    /// @notice Returns the constant for threshold value of orderId
    /// @return ORDER_ID_THRESHOLD threshold for threshold value of orderId
    function ORDER_ID_THRESHOLD() external view returns (uint32);

    /// @notice Returns the constant for threshold value of creatorId
    /// @return CREATOR_ID_THRESHOLD threshold for threshold value of creatorId
    function CREATOR_ID_THRESHOLD() external view returns (uint32);

    /// @notice The token0 (base token)
    /// @return token0 The token0 (base token) contract
    function token0() external view returns (IERC20Minimal);

    /// @notice The token1 (quote token)
    /// @return token1 The token1 (quote token) contract
    function token1() external view returns (IERC20Minimal);

    /// @notice Id of the order book
    /// @return orderBookId The unique identifier of an order book
    function orderBookId() external view returns (uint8);

    /// @notice The sizeTick of the order book
    /// @return sizeTick The sizeTick of the order book
    function sizeTick() external view returns (uint128);

    /// @notice The priceTick of the order book
    /// @return priceTick The priceTick of the order book
    function priceTick() external view returns (uint128);

    /// @notice The priceMultiplier of the order book
    /// @return priceMultiplier The priceMultiplier of the order book
    function priceMultiplier() external view returns (uint128);

    /// @notice The priceDivider of the order book
    /// @return priceDivider The priceMultiplier of the order book
    function priceDivider() external view returns (uint128);

    /// @notice Returns the id of the next order Id to create
    /// @return orderIdCounter id of the next order
    function orderIdCounter() external view returns (uint32);

    /// @notice minToken0BaseAmount minimum token0Base amount for limit order
    /// @return minToken0BaseAmount minToken0BaseAmount of the order book
    function minToken0BaseAmount() external view returns (uint64);

    /// @notice minToken1BaseAmount minimum token1Base amount (token0Base * priceBase) for limit order
    /// @return minToken1BaseAmount minToken1BaseAmount of the order book
    function minToken1BaseAmount() external view returns (uint128);

    /// @notice Claimable token0 amount for given address
    /// @return claimableToken0Balance Claimable token0 amount for given address
    function claimableToken0Balance(address owner) external view returns (uint256);

    /// @notice Claimable token1 amount for given address
    /// @return claimableToken1Balance Claimable token1 amount for given address
    function claimableToken1Balance(address owner) external view returns (uint256);

    /// @notice id of an order-owner
    /// @return addressToOwnerId id of an order-owner
    function addressToOwnerId(address owner) external view returns (uint32);

    /// @notice address for given creatorId
    /// @return addressToCreatorId address for given creatorId
    function addressToCreatorId(address creatorAddress) external view returns (uint32);

    /// @notice id of a creatorAddress
    /// @return creatorIdToAddress id of a creatorAddress
    function creatorIdToAddress(uint32 creatorId) external view returns (address);
}

File 8 of 9 : Errors.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.18;

/// @title Errors
/// @notice Library containing errors that Lighter V2 Core functions may revert with
library Errors {
    /*//////////////////////////////////////////////////////////////////////////
                                      LIGHTER-V2-FACTORY
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Thrown when `msg.sender` is not the factory owner for setOwner or createOrderBook
    error LighterV2Factory_CallerNotOwner();

    /// @notice Thrown when zero address is passed when setting the owner
    error LighterV2Factory_OwnerCannotBeZero();

    /*//////////////////////////////////////////////////////////////////////////
                                      LIGHTER-V2-CREATE-ORDER-BOOK
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Thrown when token0 and token1 are identical or zero in order book creation
    error LighterV2CreateOrderBook_InvalidTokenPair();

    /// @notice Thrown when an order book already exists with given token0 and token1 in order book creation
    error LighterV2CreateOrderBook_OrderBookAlreadyExists();

    /// @notice Thrown when order book capacity is already reached in order book creation
    error LighterV2CreateOrderBook_OrderBookIdExceedsLimit();

    /// @notice Thrown when invalid combination of logSizeTick and logPriceTick is given in order book creation
    error LighterV2CreateOrderBook_InvalidTickCombination();

    /// @notice Thrown when invalid combination of minToken0BaseAmount and minToken1BaseAmount given in order book creation
    error LighterV2CreateOrderBook_InvalidMinAmount();

    /*//////////////////////////////////////////////////////////////////////////
                                  LIGHTER-V2-ORDER
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Thrown when invalid hintId is given in limit order creation
    error LighterV2Order_InvalidHintId();

    /// @notice Thrown when given price is too small in order creation
    error LighterV2Order_PriceTooSmall();

    /// @notice Thrown when given price is too big in order creation
    error LighterV2Order_PriceTooBig();

    /// @notice Thrown when token0 or token1 amount is too small in limit order creation
    error LighterV2Order_AmountTooSmall();

    /// @notice Thrown when order capacity is already reached in order creation
    error LighterV2Order_OrderIdExceedsLimit();

    /// @notice Thrown when creator capacity is already reached in order creation
    error LighterV2Order_CreatorIdExceedsLimit();

    /// @notice Thrown when tokens sent callback is insufficient in order creation or swap
    error LighterV2Order_InsufficentCallbackTransfer();

    /// @notice Thrown when claimable balance is insufficient in order creation
    error LighterV2Order_InsufficientClaimableBalance();

    /// @notice Thrown when FillOrKill order is not fully filled
    error LighterV2Order_FoKNotFilled();

    /// @notice Thrown when contract balance decrease is larger than the transfered amount
    error LighterV2Base_ContractBalanceDoesNotMatchSentAmount();

    /// @notice Thrown when caller is not the order creator or owner in order cancelation
    error LighterV2Owner_CallerCannotCancel();

    /// @notice Thrown when caller tries to erase head or tail orders in order linked list
    error LighterV2Order_CannotEraseHeadOrTailOrders();

    /// @notice Thrown when caller tries to cancel an order that is not active
    error LighterV2Order_CannotCancelInactiveOrders();

    /// @notice Thrown when caller asks for order side for a inactive or non-existent order
    error LighterV2Order_OrderDoesNotExist();

    /// @notice Thrown when caller tries to query an order book page starting from an inactive order
    error LighterV2Order_CannotQueryFromInactiveOrder();

    /*//////////////////////////////////////////////////////////////////////////
                                  LIGHTER-SWAP
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Thrown when order book does not have enough liquidity to fill the swap
    error LighterV2Swap_NotEnoughLiquidity();

    /// @notice Thrown when swapper receives less than the minimum amount of tokens expected
    error LighterV2Swap_NotEnoughOutput();

    /// @notice Thrown when swapper needs to pay more than the maximum amount of tokens they are willing to pay
    error LighterV2Swap_TooMuchRequested();

    /*//////////////////////////////////////////////////////////////////////////
                                  LIGHTER-V2-VAULT
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Thrown when caller tries to withdraw more than their balance or withdraw zero
    error LighterV2Vault_InvalidClaimAmount();

    /// @notice Thrown when caller does not tranfer enough tokens to the vault when depositing
    error LighterV2Vault_InsufficentCallbackTransfer();
    /*//////////////////////////////////////////////////////////////////////////
                                  LIGHTER-V2-FLASH-LOAN
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Thrown when caller does not tranfer enough tokens to repay for the flash loan
    error LighterV2FlashLoan_InsufficentCallbackTransfer();

    /*//////////////////////////////////////////////////////////////////////////
                                  LIGHTER-V2-TOKEN-TRANSFER
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Thrown when token transfer from order book fails
    error LighterV2TokenTransfer_Failed();
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.18;

import "./Errors.sol";
import "../interfaces/IOrderBook.sol";

/// @title LinkedList
/// @notice Struct to use for storing sorted linked lists of ask and bid orders
struct LinkedList {
    mapping(uint32 => IOrderBook.LimitOrder) asks;
    mapping(uint32 => IOrderBook.LimitOrder) bids;
}

/// @title LinkedListLib
/// @notice Implements a sorted linked list of limit orders and provides necessary functions for order management
/// @dev Head is represented by order id 0, tail is represented by order id 1
library LinkedListLib {
    /// @notice Inserts an order into the respective linked list and keeps sorted order
    /// @param orderId id of the order to insert
    /// @param isAsk true if the order is an ask order, false if the order is a bid order
    /// @param hintId hint id of the order where the new order should be inserted to the right of
    function insert(LinkedList storage self, uint32 orderId, bool isAsk, uint32 hintId) internal {
        mapping(uint32 => IOrderBook.LimitOrder) storage orders = isAsk ? self.asks : self.bids;
        IOrderBook.LimitOrder storage order = orders[orderId];

        if (orders[hintId].next == 0) {
            revert Errors.LighterV2Order_InvalidHintId();
        }

        while (orders[hintId].ownerId == 0) {
            hintId = orders[hintId].next;
        }

        // After the search, hintId will be where the new order should be inserted to the right of
        IOrderBook.LimitOrder memory hintOrder = orders[hintId];
        while (hintId != 1) {
            IOrderBook.LimitOrder memory nextOrder = orders[hintOrder.next];
            if (isAsk ? (order.priceBase < nextOrder.priceBase) : (order.priceBase > nextOrder.priceBase)) break;
            hintId = hintOrder.next;
            hintOrder = nextOrder;
        }
        while (hintId != 0) {
            if (isAsk ? (order.priceBase >= hintOrder.priceBase) : (order.priceBase <= hintOrder.priceBase)) break;
            hintId = hintOrder.prev;
            hintOrder = orders[hintId];
        }

        order.prev = hintId;
        order.next = orders[hintId].next;
        orders[order.prev].next = orderId;
        orders[order.next].prev = orderId;
    }

    /// @notice Removes given order id from the respective linked list
    /// @dev Updates the respective linked list but does not delete the order, sets the ownerId to 0 instead
    /// @param orderId The order id to remove
    /// @param isAsk true if the order is an ask order, false if the order is a bid order
    function erase(LinkedList storage self, uint32 orderId, bool isAsk) internal {
        if (orderId <= 1) {
            revert Errors.LighterV2Order_CannotEraseHeadOrTailOrders();
        }

        mapping(uint32 => IOrderBook.LimitOrder) storage orders = isAsk ? self.asks : self.bids;

        if (orders[orderId].ownerId == 0) {
            revert Errors.LighterV2Order_CannotCancelInactiveOrders();
        }
        IOrderBook.LimitOrder storage order = orders[orderId];
        order.ownerId = 0;

        uint32 prev = order.prev;
        uint32 next = order.next;
        orders[prev].next = next;
        orders[next].prev = prev;
    }

    /// @notice Returns a struct that represents order page with given parameters
    /// @param startOrderId The order id to start the pagination from (not inclusive)
    /// @param isAsk true if the paginated orders are ask orders, false if bid orders
    /// @param limit The number of orders to return
    /// @param ownerIdToAddress Mapping from owner id to owner address
    /// @param sizeTick The size tick of the order book
    /// @param priceTick The price tick of the order book
    function getPaginatedOrders(
        LinkedList storage self,
        uint32 startOrderId,
        bool isAsk,
        uint32 limit,
        mapping(uint32 => address) storage ownerIdToAddress,
        uint128 sizeTick,
        uint128 priceTick
    ) public view returns (IOrderBook.OrderQueryItem memory paginatedOrders) {
        mapping(uint32 => IOrderBook.LimitOrder) storage orders = isAsk ? self.asks : self.bids;

        if (orders[startOrderId].ownerId == 0) {
            revert Errors.LighterV2Order_CannotQueryFromInactiveOrder();
        }
        uint32 i = 0;
        paginatedOrders.ids = new uint32[](limit);
        paginatedOrders.owners = new address[](limit);
        paginatedOrders.amount0s = new uint256[](limit);
        paginatedOrders.prices = new uint256[](limit);
        for (uint32 pointer = orders[startOrderId].next; pointer != 1 && i < limit; pointer = orders[pointer].next) {
            IOrderBook.LimitOrder memory order = orders[pointer];
            paginatedOrders.ids[i] = pointer;
            paginatedOrders.owners[i] = ownerIdToAddress[order.ownerId];
            paginatedOrders.amount0s[i] = uint256(order.amount0Base) * sizeTick;
            paginatedOrders.prices[i] = order.priceBase * priceTick;
            unchecked {
                ++i;
            }
        }
        paginatedOrders.isAsk = isAsk;
    }

    /// @notice Finds the order id where the order with given price should be inserted to the right of
    /// @param priceBase The priceBase to suggest the hintId for
    /// @return hintId The order id where the order with given price should be inserted to the right of
    function suggestHintId(LinkedList storage self, uint64 priceBase, bool isAsk) public view returns (uint32) {
        mapping(uint32 => IOrderBook.LimitOrder) storage orders = isAsk ? self.asks : self.bids;
        uint32 hintOrderId = 0;
        IOrderBook.LimitOrder memory hintOrder = orders[hintOrderId];
        while (hintOrderId != 1) {
            IOrderBook.LimitOrder memory nextOrder = orders[hintOrder.next];
            if (isAsk ? (priceBase < nextOrder.priceBase) : (priceBase > nextOrder.priceBase)) break;
            hintOrderId = hintOrder.next;
            hintOrder = nextOrder;
        }
        return hintOrderId;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 4150
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {
    "contracts/libraries/LinkedList.sol": {
      "LinkedListLib": "0x43ccc6d2a517a9a0955fba24c73f2202da5af8b3"
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"uint8","name":"_orderBookId","type":"uint8"},{"internalType":"address","name":"_token0Address","type":"address"},{"internalType":"address","name":"_token1Address","type":"address"},{"internalType":"uint8","name":"_logSizeTick","type":"uint8"},{"internalType":"uint8","name":"_logPriceTick","type":"uint8"},{"internalType":"uint64","name":"_minToken0BaseAmount","type":"uint64"},{"internalType":"uint128","name":"_minToken1BaseAmount","type":"uint128"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"LighterV2Base_ContractBalanceDoesNotMatchSentAmount","type":"error"},{"inputs":[],"name":"LighterV2CreateOrderBook_InvalidMinAmount","type":"error"},{"inputs":[],"name":"LighterV2CreateOrderBook_InvalidTickCombination","type":"error"},{"inputs":[],"name":"LighterV2FlashLoan_InsufficentCallbackTransfer","type":"error"},{"inputs":[],"name":"LighterV2Order_AmountTooSmall","type":"error"},{"inputs":[],"name":"LighterV2Order_CannotCancelInactiveOrders","type":"error"},{"inputs":[],"name":"LighterV2Order_CannotEraseHeadOrTailOrders","type":"error"},{"inputs":[],"name":"LighterV2Order_CreatorIdExceedsLimit","type":"error"},{"inputs":[],"name":"LighterV2Order_FoKNotFilled","type":"error"},{"inputs":[],"name":"LighterV2Order_InsufficentCallbackTransfer","type":"error"},{"inputs":[],"name":"LighterV2Order_InsufficientClaimableBalance","type":"error"},{"inputs":[],"name":"LighterV2Order_InvalidHintId","type":"error"},{"inputs":[],"name":"LighterV2Order_OrderDoesNotExist","type":"error"},{"inputs":[],"name":"LighterV2Order_OrderIdExceedsLimit","type":"error"},{"inputs":[],"name":"LighterV2Order_PriceTooBig","type":"error"},{"inputs":[],"name":"LighterV2Order_PriceTooSmall","type":"error"},{"inputs":[],"name":"LighterV2Owner_CallerCannotCancel","type":"error"},{"inputs":[],"name":"LighterV2Swap_NotEnoughLiquidity","type":"error"},{"inputs":[],"name":"LighterV2Swap_NotEnoughOutput","type":"error"},{"inputs":[],"name":"LighterV2Swap_TooMuchRequested","type":"error"},{"inputs":[],"name":"LighterV2TokenTransfer_Failed","type":"error"},{"inputs":[],"name":"LighterV2Vault_InsufficentCallbackTransfer","type":"error"},{"inputs":[],"name":"LighterV2Vault_InvalidClaimAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"id","type":"uint32"}],"name":"CancelLimitOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountDelta","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isToken0","type":"bool"}],"name":"ClaimableBalanceDecrease","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountDelta","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isToken0","type":"bool"}],"name":"ClaimableBalanceIncrease","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint32","name":"id","type":"uint32"},{"indexed":false,"internalType":"uint64","name":"amount0Base","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"priceBase","type":"uint64"},{"indexed":false,"internalType":"bool","name":"isAsk","type":"bool"},{"indexed":false,"internalType":"enum IOrderBook.OrderType","name":"orderType","type":"uint8"}],"name":"CreateOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"FlashLoan","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"askId","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"bidId","type":"uint32"},{"indexed":false,"internalType":"address","name":"askOwner","type":"address"},{"indexed":false,"internalType":"address","name":"bidOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"bool","name":"isExactInput","type":"bool"},{"indexed":false,"internalType":"bool","name":"isAsk","type":"bool"},{"indexed":false,"internalType":"uint256","name":"swapAmount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"swapAmount1","type":"uint256"}],"name":"SwapExactAmount","type":"event"},{"inputs":[],"name":"CREATOR_ID_THRESHOLD","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LOG10_TICK_THRESHOLD","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PRICE","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORDER_ID_THRESHOLD","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"addressToCreatorId","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"addressToOwnerId","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"address","name":"owner","type":"address"}],"name":"cancelLimitOrder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountToClaim","type":"uint256"},{"internalType":"bool","name":"isToken0","type":"bool"}],"name":"claimToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimableToken0Balance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimableToken1Balance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"amount0Base","type":"uint64"},{"internalType":"uint64","name":"priceBase","type":"uint64"},{"internalType":"bool","name":"isAsk","type":"bool"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"hintId","type":"uint32"},{"internalType":"enum IOrderBook.OrderType","name":"orderType","type":"uint8"},{"internalType":"bytes","name":"callbackData","type":"bytes"}],"name":"createOrder","outputs":[{"internalType":"uint32","name":"newOrderId","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"creatorIdToAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountToDeposit","type":"uint256"},{"internalType":"bool","name":"isToken0","type":"bool"},{"internalType":"bytes","name":"callbackData","type":"bytes"}],"name":"depositToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"},{"internalType":"bytes","name":"callbackData","type":"bytes"}],"name":"flashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isAsk","type":"bool"},{"internalType":"uint32","name":"id","type":"uint32"}],"name":"getLimitOrder","outputs":[{"components":[{"internalType":"uint32","name":"perfMode_creatorId","type":"uint32"},{"internalType":"uint32","name":"prev","type":"uint32"},{"internalType":"uint32","name":"next","type":"uint32"},{"internalType":"uint32","name":"ownerId","type":"uint32"},{"internalType":"uint64","name":"amount0Base","type":"uint64"},{"internalType":"uint64","name":"priceBase","type":"uint64"}],"internalType":"struct IOrderBook.LimitOrder","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"takerOrderAmount0Base","type":"uint64"},{"internalType":"uint64","name":"takerOrderPriceBase","type":"uint64"},{"internalType":"uint64","name":"makerOrderAmount0Base","type":"uint64"},{"internalType":"uint64","name":"makerOrderPriceBase","type":"uint64"},{"internalType":"bool","name":"isTakerAsk","type":"bool"}],"name":"getLimitOrderSwapAmounts","outputs":[{"internalType":"uint64","name":"amount0BaseReturn","type":"uint64"},{"internalType":"uint128","name":"amount1BaseReturn","type":"uint128"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint32","name":"startOrderId","type":"uint32"},{"internalType":"bool","name":"isAsk","type":"bool"},{"internalType":"uint32","name":"limit","type":"uint32"}],"name":"getPaginatedOrders","outputs":[{"components":[{"internalType":"bool","name":"isAsk","type":"bool"},{"internalType":"uint32[]","name":"ids","type":"uint32[]"},{"internalType":"address[]","name":"owners","type":"address[]"},{"internalType":"uint256[]","name":"amount0s","type":"uint256[]"},{"internalType":"uint256[]","name":"prices","type":"uint256[]"}],"internalType":"struct IOrderBook.OrderQueryItem","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"bool","name":"isAsk","type":"bool"},{"internalType":"uint64","name":"makerAmount0Base","type":"uint64"},{"internalType":"uint64","name":"makerPriceBase","type":"uint64"}],"name":"getSwapAmountsForToken0","outputs":[{"internalType":"uint256","name":"swapAmount0","type":"uint256"},{"internalType":"uint256","name":"swapAmount1","type":"uint256"},{"internalType":"uint64","name":"amount0BaseDelta","type":"uint64"},{"internalType":"bool","name":"fullTakerFill","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount1","type":"uint256"},{"internalType":"bool","name":"isAsk","type":"bool"},{"internalType":"uint64","name":"makerAmount0Base","type":"uint64"},{"internalType":"uint64","name":"makerPriceBase","type":"uint64"}],"name":"getSwapAmountsForToken1","outputs":[{"internalType":"uint256","name":"swapAmount0","type":"uint256"},{"internalType":"uint256","name":"swapAmount1","type":"uint256"},{"internalType":"uint64","name":"amount0BaseDelta","type":"uint64"},{"internalType":"bool","name":"fullTakerFill","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"id","type":"uint32"}],"name":"isAskOrder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"id","type":"uint32"}],"name":"isOrderActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minToken0BaseAmount","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minToken1BaseAmount","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"orderBookId","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"orderIdCounter","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"ownerIdToAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceDivider","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceMultiplier","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceTick","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sizeTick","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"priceBase","type":"uint64"},{"internalType":"bool","name":"isAsk","type":"bool"}],"name":"suggestHintId","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"isAsk","type":"bool"},{"internalType":"bool","name":"isExactInput","type":"bool"},{"internalType":"uint256","name":"exactAmount","type":"uint256"},{"internalType":"uint256","name":"expectedAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"callbackData","type":"bytes"}],"name":"swapExactSingle","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token0","outputs":[{"internalType":"contract IERC20Minimal","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token1","outputs":[{"internalType":"contract IERC20Minimal","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

6101a06040523480156200001257600080fd5b5060405162005ceb38038062005ceb8339810160408190526200003591620008c6565b600160009081556001600160a01b03808816608081905290871660a05260ff891660c0526040805163313ce56760e01b8152905163313ce56791600480820192602092909190829003018187875af115801562000096573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000bc919062000979565b9050602660ff8616101580620000d65750602660ff851610155b15620000f5576040516337d89f8960e01b815260040160405180910390fd5b6200010285600a62000ab3565b6001600160801b0316610120526200011c84600a62000ab3565b6001600160801b03166101405260018060ff83166200013c878962000ac4565b60ff1610620001b05760268362000154888a62000ac4565b62000160919062000ae0565b60ff161062000182576040516337d89f8960e01b815260040160405180910390fd5b826200018f878962000ac4565b6200019b919062000ae0565b620001a890600a62000ab3565b915062000216565b602686620001bf898662000ae0565b620001cb919062000ae0565b60ff1610620001ed576040516337d89f8960e01b815260040160405180910390fd5b86620001fa878562000ae0565b62000206919062000ae0565b6200021390600a62000ab3565b90505b6001600160801b03808316610160528116610180526001600160401b03851615806200024957506001600160801b038416155b15620002685760405163bd35b3bb60e01b815260040160405180910390fd5b846001600160401b031660e0816001600160401b031681525050836001600160801b0316610100816001600160801b0316815250506040518060c00160405280600063ffffffff168152602001600063ffffffff168152602001600163ffffffff168152602001600163ffffffff16815260200160006001600160401b0316815260200160006001600160401b0316815250600260000160008063ffffffff16815260200190815260200160002060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160000160106101000a8154816001600160401b0302191690836001600160401b0316021790555060a08201518160000160186101000a8154816001600160401b0302191690836001600160401b031602179055509050506040518060c00160405280600063ffffffff168152602001600063ffffffff168152602001600163ffffffff168152602001600163ffffffff16815260200160006001600160401b031681526020016001600160401b03801681525060026000016000600163ffffffff16815260200190815260200160002060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160000160106101000a8154816001600160401b0302191690836001600160401b0316021790555060a08201518160000160186101000a8154816001600160401b0302191690836001600160401b031602179055509050506040518060c00160405280600063ffffffff168152602001600063ffffffff168152602001600163ffffffff168152602001600163ffffffff16815260200160006001600160401b031681526020016001600160401b038016815250600260010160008063ffffffff16815260200190815260200160002060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160000160106101000a8154816001600160401b0302191690836001600160401b0316021790555060a08201518160000160186101000a8154816001600160401b0302191690836001600160401b031602179055509050506040518060c00160405280600063ffffffff168152602001600063ffffffff168152602001600163ffffffff168152602001600163ffffffff16815260200160006001600160401b0316815260200160006001600160401b031681525060026001016000600163ffffffff16815260200190815260200160002060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160000160106101000a8154816001600160401b0302191690836001600160401b0316021790555060a08201518160000160186101000a8154816001600160401b0302191690836001600160401b031602179055509050506002600160006101000a81548163ffffffff021916908363ffffffff1602179055505050505050505050505062000afc565b805160ff81168114620008a957600080fd5b919050565b80516001600160a01b0381168114620008a957600080fd5b600080600080600080600060e0888a031215620008e257600080fd5b620008ed8862000897565b9650620008fd60208901620008ae565b95506200090d60408901620008ae565b94506200091d6060890162000897565b93506200092d6080890162000897565b60a08901519093506001600160401b03811681146200094b57600080fd5b60c08901519092506001600160801b03811681146200096957600080fd5b8091505092959891949750929550565b6000602082840312156200098c57600080fd5b620009978262000897565b9392505050565b634e487b7160e01b600052601160045260246000fd5b600181815b80851115620009f5578160001904821115620009d957620009d96200099e565b80851615620009e757918102915b93841c9390800290620009b9565b509250929050565b60008262000a0e5750600162000aad565b8162000a1d5750600062000aad565b816001811462000a36576002811462000a415762000a61565b600191505062000aad565b60ff84111562000a555762000a556200099e565b50506001821b62000aad565b5060208310610133831016604e8410600b841016171562000a86575081810a62000aad565b62000a928383620009b4565b806000190482111562000aa95762000aa96200099e565b0290505b92915050565b60006200099760ff841683620009fd565b60ff818116838216019081111562000aad5762000aad6200099e565b60ff828116828216039081111562000aad5762000aad6200099e565b60805160a05160c05160e051610100516101205161014051610160516101805161505862000c936000396000818161037c01528181610baf01528181610c2301528181610cd8015281816112210152818161161201528181611ca4015281816122b30152612cd40152600081816106b601528181610bd401528181610c4701528181610d020152818161163c01528181611cce015281816122dd0152612cfc01526000818161040c015261252b0152600081816102db01528181610d6d015281816116a701528181611bd101528181611c0401528181611c7001528181612199015281816125030152612c7d01526000818161029c01526113b10152600081816104c4015261136c015260006104eb0152600081816105ea0152818161073c01528181610e6101528181610f34015281816110c301528181611e4b015281816123570152818161319f015261321a01526000818161025d0152818161076201528181610dcb01528181610ede0152818161100001528181611dd0015281816121f0015281816131c501526131f401526150586000f3fe608060405234801561001057600080fd5b50600436106102265760003560e01c80639087f4741161012a578063be374423116100bd578063d2f2b7661161008c578063d50cb88b11610071578063d50cb88b146106b1578063d819e812146106d8578063e4ae2e281461070157600080fd5b8063d2f2b7661461060c578063d4105e5d1461068957600080fd5b8063be374423146105aa578063cd6c78d0146105ba578063d0e76269146105da578063d21220a7146105e557600080fd5b8063a89883a2116100f9578063a89883a214610546578063b2d6d47514610566578063b866365a1461058c578063b90f2a401461059f57600080fd5b80639087f474146104e657806392250a471461050d57806396e7952e14610520578063a29d824c1461053357600080fd5b8063365044a8116101bd578063620a92351161018c5780637f2ac67a116101715780637f2ac67a14610486578063818748bd14610499578063829d600a146104bf57600080fd5b8063620a92351461042e578063679f05791461047357600080fd5b8063365044a81461037757806348e057ed1461039e57806349d79bc4146103cc5780634a9f29601461040757600080fd5b80632a2ef375116101f95780632a2ef375146102fd5780632cea5cd3146103125780632e53eda51461033557806334d441d31461035d57600080fd5b806301c11d961461022b5780630dfe16811461025857806320957ed31461029757806327d7d68e146102d6575b600080fd5b61023a67ffffffffffffffff81565b60405167ffffffffffffffff90911681526020015b60405180910390f35b61027f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161024f565b6102be7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160801b03909116815260200161024f565b6102be7f000000000000000000000000000000000000000000000000000000000000000081565b61031061030b366004614588565b61072a565b005b6103256103203660046145f3565b6109d8565b604051901515815260200161024f565b61034861034336600461462d565b610a42565b60405163ffffffff909116815260200161024f565b610365602681565b60405160ff909116815260200161024f565b6102be7f000000000000000000000000000000000000000000000000000000000000000081565b6103be6103ac366004614679565b60056020526000908152604090205481565b60405190815260200161024f565b6103df6103da366004614696565b610af3565b6040805167ffffffffffffffff90931683526001600160801b0390911660208301520161024f565b6102be7f000000000000000000000000000000000000000000000000000000000000000081565b61044161043c3660046146ff565b610b9b565b60405161024f9493929190938452602084019290925267ffffffffffffffff1660408301521515606082015260800190565b61031061048136600461474e565b610dab565b6103486104943660046147e4565b6111c7565b6103486104a7366004614679565b60076020526000908152604090205463ffffffff1681565b61023a7f000000000000000000000000000000000000000000000000000000000000000081565b6103657f000000000000000000000000000000000000000000000000000000000000000081565b61044161051b3660046146ff565b611bb6565b61031061052e366004614891565b611d38565b6103256105413660046148b6565b611f1a565b6103be610554366004614679565b60046020526000908152604090205481565b610348610574366004614679565b60086020526000908152604090205463ffffffff1681565b61032561059a3660046145f3565b612426565b61034863ffffffff81565b6001546103489063ffffffff1681565b6105cd6105c83660046148e4565b612475565b60405161024f91906149a3565b610348637fffffff81565b61027f7f000000000000000000000000000000000000000000000000000000000000000081565b61061f61061a366004614a5d565b6125be565b60405161024f9190600060c08201905063ffffffff80845116835280602085015116602084015280604085015116604084015280606085015116606084015250608083015167ffffffffffffffff80821660808501528060a08601511660a0850152505092915050565b61069c610697366004614a8b565b61269b565b6040805192835260208301919091520161024f565b6102be7f000000000000000000000000000000000000000000000000000000000000000081565b61027f6106e63660046145f3565b6006602052600090815260409020546001600160a01b031681565b61027f61070f3660046145f3565b6009602052600090815260409020546001600160a01b031681565b610732612792565b33600083610760577f0000000000000000000000000000000000000000000000000000000000000000610782565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156107cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f09190614b12565b6040517f727f979c0000000000000000000000000000000000000000000000000000000081529091506001600160a01b0384169063727f979c9061083c90899086908990600401614b2b565b600060405180830381600087803b15801561085657600080fd5b505af115801561086a573d6000803e3d6000fd5b50505050858161087a9190614ba7565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156108be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e29190614b12565b101561091a576040517fe827b48700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8415610953576001600160a01b03831660009081526004602052604081208054889290610948908490614ba7565b909155506109819050565b6001600160a01b0383166000908152600560205260408120805488929061097b908490614ba7565b90915550505b6040805187815286151560208201526001600160a01b038516917ff939ff49cec37eed853259ac7b9b4c0a8c7aacb9feca8467b3d54512ba26429a910160405180910390a25050506109d36001600055565b505050565b60006109e382612426565b610a19576040517f7312861b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5063ffffffff9081166000908152600260205260409020546001600160601b9091049091161190565b6040517fd271c2c20000000000000000000000000000000000000000000000000000000081526002600482015267ffffffffffffffff8316602482015281151560448201526000907343ccc6d2a517a9a0955fba24c73f2202da5af8b39063d271c2c290606401602060405180830381865af4158015610ac6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aea9190614bba565b90505b92915050565b600080828015610b1757508567ffffffffffffffff168467ffffffffffffffff1610155b80610b3f575082158015610b3f57508367ffffffffffffffff168667ffffffffffffffff1610155b15610b8a578467ffffffffffffffff168767ffffffffffffffff161015610b6857869150610b6c565b8491505b81610b778582614bd7565b67ffffffffffffffff1691509150610b91565b5060009050805b9550959350505050565b600080808080610c11896001600160801b037f000000000000000000000000000000000000000000000000000000000000000016610c037f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff8b16614c03565b6001600160801b031661280a565b90508715610ca7576001600160801b037f00000000000000000000000000000000000000000000000000000000000000008116907f000000000000000000000000000000000000000000000000000000000000000016610c7b67ffffffffffffffff891684614c26565b610c859190614c26565b610c8f9190614c53565b935088841015610ca757610ca4600182614ba7565b90505b8667ffffffffffffffff16811115610cce57506000905067ffffffffffffffff8616610cd3565b600191505b8092507f00000000000000000000000000000000000000000000000000000000000000006001600160801b03167f00000000000000000000000000000000000000000000000000000000000000006001600160801b03168767ffffffffffffffff168567ffffffffffffffff16610d4a9190614c26565b610d549190614c26565b610d5e9190614c53565b9350610d9d6001600160801b037f00000000000000000000000000000000000000000000000000000000000000001667ffffffffffffffff8516614c26565b945050945094509450949050565b610db3612792565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610e1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3e9190614b12565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610ea8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ecc9190614b12565b9050600086118015610f065750610f047f00000000000000000000000000000000000000000000000000000000000000008888612916565b155b15610f24576040516309e1fb8b60e31b815260040160405180910390fd5b600085118015610f5c5750610f5a7f00000000000000000000000000000000000000000000000000000000000000008887612916565b155b15610f7a576040516309e1fb8b60e31b815260040160405180910390fd5b6040517f8f36f6400000000000000000000000000000000000000000000000000000000081523390638f36f64090610fb89087908790600401614c75565b600060405180830381600087803b158015610fd257600080fd5b505af1158015610fe6573d6000803e3d6000fd5b50506040516370a0823160e01b81523060048201528492507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691506370a0823190602401602060405180830381865afa158015611050573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110749190614b12565b10156110ac576040517fed7735c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611112573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111369190614b12565b101561116e576040517fed7735c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051878152602081018790526001600160a01b0389169133917f0d7d75e01ab95780d3cd1c8ec0dd6c2ce19e3a20427eec8bf53283b6fb8e95f0910160405180910390a350506111c06001600055565b5050505050565b60006111d1612792565b5060015463ffffffff1667ffffffffffffffff881660000361121f576040517fcdf6143100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160801b03168767ffffffffffffffff16101561128c576040517f807a1e5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000167ffffffffffffffff8816016112ef576040517f6c84672900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083600381111561130357611303614ca4565b14806113205750600183600381111561131e5761131e614ca4565b145b1561141e578063ffffffff168463ffffffff161061136a576040517f6a118cfc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff168867ffffffffffffffff1610806113e757506001600160801b037f0000000000000000000000000000000000000000000000000000000000000000166113db8989614bd7565b67ffffffffffffffff16105b1561141e576040517fcdf6143100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915263ffffffff8281161061148f576040517f853a5ad000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61149a826001614cba565b6001805463ffffffff191663ffffffff9283161790556040805160c081018252600080825260208201819052818301819052606082015267ffffffffffffffff8c811660808301528b1660a08201529051909250908316906001600160a01b038816907f7206876180a726787edf45582daa9f64c66460c7f389385372099aa4c64343f090611530908d908d908d908b90614cde565b60405180910390a360008060008061154a85878c8e612ae7565b92965090945092509050600288600381111561156857611568614ca4565b14801561158357506000856080015167ffffffffffffffff16115b156115ba576040517f917126fd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808960038111156115cf576115cf614ca4565b14806115ec575060018960038111156115ea576115ea614ca4565b145b801561160657506000866080015167ffffffffffffffff16115b156116eb578b6116a5577f00000000000000000000000000000000000000000000000000000000000000006001600160801b03167f00000000000000000000000000000000000000000000000000000000000000006001600160801b03168760a0015167ffffffffffffffff16886080015167ffffffffffffffff1661168c9190614c26565b6116969190614c26565b6116a09190614c53565b6116e8565b7f00000000000000000000000000000000000000000000000000000000000000006001600160801b0316866080015167ffffffffffffffff166116e89190614c26565b90505b60008511806116fa5750600084115b806117165750600089600381111561171457611714614ca4565b145b806117325750600189600381111561173057611730614ca4565b145b156117a8576040805161012081019091528c151581526117a8906020810160018c600381111561176457611764614ca4565b14151581526020018d6001600160a01b031681526020018781526020018681526020018381526020018563ffffffff1681526020018481526020018a815250613194565b8015611b9b576001600160a01b038b1660009081526007602052604081205463ffffffff166060880181905290036118455763ffffffff8716606087018190526001600160a01b038c166000818152600760209081526040808320805463ffffffff191686179055938252600690529190912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690911790555b336001600160a01b038c1614611929573360009081526008602052604081205463ffffffff16808852900361191b57637fffffff63ffffffff8816106118b7576040517fd1cd82ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff808816808852336000818152600860209081526040808320805463ffffffff19169095179094558a5190941681526009909352912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690911790555b855160011b63fffffffe1686525b600189600381111561193d5761193d614ca4565b0361195057855160011763ffffffff1686525b8b15611a7a5763ffffffff8088166000908152600260208181526040928390208a518154928c0151948c015160608d015160808e015160a08f015167ffffffffffffffff908116600160c01b0277ffffffffffffffffffffffffffffffffffffffffffffffff91909216600160801b02166001600160801b03928a16600160601b026fffffffff00000000000000000000000019948b166801000000000000000002949094167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998b16640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909816958b169590951796909617979097169290921717169190911792909217909155611a759189908f908e9061377216565b611b9b565b63ffffffff80881660009081526003602090815260409182902089518154928b0151938b015160608c015160808d015160a08e015167ffffffffffffffff908116600160c01b0277ffffffffffffffffffffffffffffffffffffffffffffffff91909216600160801b02166001600160801b03928916600160601b026fffffffff00000000000000000000000019948a166801000000000000000002949094167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff988a16640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909816958a1695909517969096179690961692909217171691909117919091179055611b9b9060029089908f908e9061377216565b505050505050611bab6001600055565b979650505050505050565b60008060008060008715611bfe57611bf76001600160801b037f0000000000000000000000000000000000000000000000000000000000000000168a614c53565b9050611c34565b611c31897f00000000000000000000000000000000000000000000000000000000000000006001600160801b0316613b63565b90505b8667ffffffffffffffff16811115611c5b57506000905067ffffffffffffffff8616611c60565b600191505b915081611ca06001600160801b037f00000000000000000000000000000000000000000000000000000000000000001667ffffffffffffffff8316614c26565b94507f00000000000000000000000000000000000000000000000000000000000000006001600160801b03167f00000000000000000000000000000000000000000000000000000000000000006001600160801b03168767ffffffffffffffff168567ffffffffffffffff16611d169190614c26565b611d209190614c26565b611d2a9190614c53565b935050945094509450949050565b611d40612792565b33600082611d66576001600160a01b038216600090815260056020526040902054611d80565b6001600160a01b0382166000908152600460205260409020545b9050600084118015611d925750808411155b15611ed8578215611e18576001600160a01b03821660009081526004602052604081208054869290611dc5908490614d2c565b90915550611df690507f00000000000000000000000000000000000000000000000000000000000000008386612916565b611e13576040516309e1fb8b60e31b815260040160405180910390fd5b611e8e565b6001600160a01b03821660009081526005602052604081208054869290611e40908490614d2c565b90915550611e7190507f00000000000000000000000000000000000000000000000000000000000000008386612916565b611e8e576040516309e1fb8b60e31b815260040160405180910390fd5b6040805185815284151560208201526001600160a01b038416917fccd5b8d697ca09c88b66c7bd627d6bb0c9a161861c693df7fdb380d758b2257a910160405180910390a2611f0a565b6040517f9db10d0100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050611f166001600055565b5050565b6000611f24612792565b611f2d83612426565b611f395750600061241c565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905290611f74856109d8565b905080156120085763ffffffff808616600090815260026020908152604091829020825160c081018452905480851682526401000000008104851692820192909252680100000000000000008204841692810192909252600160601b8104909216606082015267ffffffffffffffff600160801b830481166080830152600160c01b90920490911660a08201529150612090565b63ffffffff808616600090815260036020908152604091829020825160c081018452905480851682526401000000008104851692820192909252680100000000000000008204841692810192909252600160601b8104909216606082015267ffffffffffffffff600160801b830481166080830152600160c01b90920490911660a082015291505b606082015163ffffffff1660009081526006602052604090205482516001600160a01b039091169060011c637fffffff168181156120e9575063ffffffff81166000908152600960205260409020546001600160a01b03165b826001600160a01b0316876001600160a01b03161415806121275750336001600160a01b038216148015906121275750336001600160a01b03841614155b1561215e576040517fa934f3c200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405163ffffffff8916907ff584155be07e1a74cb2bc291299df861c09f00cbc773d1509595ed4ff938398f90600090a283156122af5760007f00000000000000000000000000000000000000000000000000000000000000006001600160801b0316866080015167ffffffffffffffff166121da9190614c26565b86519091506000906001168103612219576122167f00000000000000000000000000000000000000000000000000000000000000008684612916565b90505b8061229c576001600160a01b03851660009081526004602052604081208054849290612246908490614ba7565b9091555050865160011660000361229c5760408051838152600160208201526001600160a01b038716917ff939ff49cec37eed853259ac7b9b4c0a8c7aacb9feca8467b3d54512ba26429a910160405180910390a25b6122a860028b88613b9a565b5050612412565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160801b03167f00000000000000000000000000000000000000000000000000000000000000006001600160801b03168760a0015167ffffffffffffffff16886080015167ffffffffffffffff1661232d9190614c26565b6123379190614c26565b6123419190614c53565b865190915060009060011681036123805761237d7f00000000000000000000000000000000000000000000000000000000000000008684612916565b90505b80612403576001600160a01b038516600090815260056020526040812080548492906123ad908490614ba7565b909155505086516001166000036124035760408051838152600060208201526001600160a01b038716917ff939ff49cec37eed853259ac7b9b4c0a8c7aacb9feca8467b3d54512ba26429a910160405180910390a25b61240f60028b88613b9a565b50505b6001955050505050505b610aed6001600055565b63ffffffff8082166000908152600260205260408120549091600160601b90910416151580610aed57505063ffffffff908116600090815260036020526040902054600160601b900416151590565b6124a96040518060a00160405280600015158152602001606081526020016060815260200160608152602001606081525090565b6040517f91bf05e50000000000000000000000000000000000000000000000000000000081526002600482015263ffffffff8086166024830152841515604483015283166064820152600660848201526001600160801b037f0000000000000000000000000000000000000000000000000000000000000000811660a48301527f00000000000000000000000000000000000000000000000000000000000000001660c48201527343ccc6d2a517a9a0955fba24c73f2202da5af8b3906391bf05e59060e401600060405180830381865af415801561258c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125b49190810190614ea1565b90505b9392505050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091528261260f5763ffffffff82166000908152600360205260409020612625565b63ffffffff821660009081526002602052604090205b6040805160c081018252915463ffffffff8082168452640100000000820481166020850152680100000000000000008204811692840192909252600160601b8104909116606083015267ffffffffffffffff600160801b820481166080840152600160c01b9091041660a0820152905092915050565b6000806126a6612792565b6000806000806126b98c8c8c8c8c613cd6565b935093509350935061271e6040518061012001604052808e151581526020016000151581526020018a6001600160a01b03168152602001868152602001858152602001600081526020018463ffffffff16815260200183815260200189815250613194565b604080518c151581528d15156020820152908101859052606081018490526001600160a01b0389169033907fd1a5d53e1dd2f18ece2c41d1516ce4335c4022b00735378ec82a4eb657724bb29060800160405180910390a3509193509150506127876001600055565b965096945050505050565b600260005403612803576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b6002600055565b60008080600019858709858702925082811083820303915050806000036128445783828161283a5761283a614c3d565b04925050506125b7565b8084116128ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f77000000000000000000000060448201526064016127fa565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6040516370a0823160e01b815230600482015260009081906001600160a01b038616906370a0823190602401602060405180830381865afa15801561295f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129839190614b12565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526024820186905291925060009187169063a9059cbb906044016020604051808303816000875af1925050508015612a0d575060408051601f3d908101601f19168201909252612a0a91810190614f8b565b60015b612a1957506000612a1c565b90505b600081612a2a576000612a2c565b845b6040516370a0823160e01b8152306004820152909150839082906001600160a01b038a16906370a0823190602401602060405180830381865afa158015612a77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a9b9190614b12565b612aa59190614ba7565b1015612add576040517f4ad2d0b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5095945050505050565b604080516101e08101825260008082526020820181905291810182905260608181018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201839052610160820183905261018082018390526101a082018390526101c082018190528291829190600086612b73576002612b76565b60035b60008080526020829052604090205468010000000000000000900463ffffffff16835290505b816000015163ffffffff16600114158015612bc5575060008a6080015167ffffffffffffffff16115b1561310a57815163ffffffff9081166000908152602083815260408083208054600160601b81049095168452600683529220546001600160a01b03169085015260808c015160a08d01519192612c37929067ffffffffffffffff600160801b8204811691600160c01b9004168c610af3565b6001600160801b031661012085015267ffffffffffffffff1661010084018190521580612c7057506101208301516001600160801b0316155b15612c7b575061310a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160801b031683610100015167ffffffffffffffff16612cbf9190614c26565b60c08401526101208301516001600160801b037f0000000000000000000000000000000000000000000000000000000000000000811691612d24917f000000000000000000000000000000000000000000000000000000000000000081169116614c26565b612d2e9190614c53565b60e08401528715612dbd57826000015163ffffffff168a63ffffffff167fbd8e28ca9aa9ef3945b1e218ce096cb31c1e6ed750c5d1dea41832b27c208ed28b86602001518760c001518860e00151604051612db094939291906001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b60405180910390a3612e2f565b825160208085015160c086015160e0870151604080516001600160a01b039485168152938f169484019490945292820152606081019190915263ffffffff808d169216907fbd8e28ca9aa9ef3945b1e218ce096cb31c1e6ed750c5d1dea41832b27c208ed29060800160405180910390a35b8260c001518360400151612e439190614ba7565b604084015260e08301516060840151612e5c9190614ba7565b60608401526101a083015161018084015163ffffffff918216911603612f9d576101a083015160049063ffffffff1615612ea4576101a0840151612ea1906002614fa8565b90505b60008163ffffffff1667ffffffffffffffff811115612ec557612ec56144a8565b604051908082528060200260200182016040528015612f1057816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181612ee35790505b50905060005b856101a0015163ffffffff168163ffffffff161015612f8957856101c001518163ffffffff1681518110612f4c57612f4c614fc8565b6020026020010151828263ffffffff1681518110612f6c57612f6c614fc8565b6020908102919091010152612f82600182614cba565b9050612f16565b506101c085015263ffffffff166101a08401525b604051806060016040528084602001516001600160a01b0316815260200189612fca578460e00151612fd0565b8460c001515b815282546001908116146020909101526101c08401516101808501805190612ff782614fde565b63ffffffff1663ffffffff1681525063ffffffff168151811061301c5761301c614fc8565b60200260200101819052508261010001518b6080015161303c9190615001565b67ffffffffffffffff90811660808d01526101008401518254908216600160801b9091049091160361308c57600161014084015280546fffffffff000000000000000000000000191681556130f0565b61010083015181546130af9190600160801b900467ffffffffffffffff16615001565b815467ffffffffffffffff91909116600160801b027fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff90911617905561310a565b5468010000000000000000900463ffffffff168252612b9c565b8161014001511561316a57815163ffffffff908116600090815260208390526040808220805467ffffffff00000000191690558451828052912080549190921668010000000000000000026bffffffff0000000000000000199091161790555b50604081015160608201516101808301516101c090930151919b909a509198509650945050505050565b80516000906131c3577f00000000000000000000000000000000000000000000000000000000000000006131e5565b7f00000000000000000000000000000000000000000000000000000000000000005b905060008260000151613218577f000000000000000000000000000000000000000000000000000000000000000061323a565b7f00000000000000000000000000000000000000000000000000000000000000005b905060008360a00151846000015161325657846080015161325c565b84606001515b6132669190614ba7565b90506000846000015161327d578460600151613283565b84608001515b9050801561332b578460200151156132ff578451156132d3576040808601516001600160a01b03166000908152600560205290812080548392906132c8908490614ba7565b9091555061332b9050565b6040808601516001600160a01b03166000908152600460205290812080548392906132c8908490614ba7565b61330e83866040015183612916565b61332b576040516309e1fb8b60e31b815260040160405180910390fd5b846020015115613417578451156133af5733600090815260046020526040902054821115613385576040517fedb4840900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260046020526040812080548492906133a4908490614d2c565b909155506135a99050565b336000908152600560205260409020548211156133f8576040517fedb4840900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260056020526040812080548492906133a4908490614d2c565b6040516370a0823160e01b81523060048201526000906001600160a01b038616906370a0823190602401602060405180830381865afa15801561345e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134829190614b12565b6101008701516040517f727f979c000000000000000000000000000000000000000000000000000000008152919250339163727f979c916134c99187918a91600401614b2b565b600060405180830381600087803b1580156134e357600080fd5b505af11580156134f7573d6000803e3d6000fd5b5050505082816135079190614ba7565b6040516370a0823160e01b81523060048201526001600160a01b038716906370a0823190602401602060405180830381865afa15801561354b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061356f9190614b12565b10156135a7576040517f07bb680200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b60005b8560c0015163ffffffff168163ffffffff16101561376a5760008660e001518263ffffffff16815181106135e2576135e2614fc8565b60200260200101519050806040015115613668578651156136385760208082015182516001600160a01b0316600090815260049092526040822080549192909161362d908490614ba7565b909155506137599050565b60208082015182516001600160a01b0316600090815260059092526040822080549192909161362d908490614ba7565b600061367d8783600001518460200151612916565b905080613757578751156136c65760208083015183516001600160a01b031660009081526004909252604082208054919290916136bb908490614ba7565b909155506136fc9050565b60208083015183516001600160a01b031660009081526005909252604082208054919290916136f6908490614ba7565b90915550505b81600001516001600160a01b03167ff939ff49cec37eed853259ac7b9b4c0a8c7aacb9feca8467b3d54512ba26429a83602001518a6000015160405161374e9291909182521515602082015260400190565b60405180910390a25b505b5061376381614fde565b90506135ac565b505050505050565b6000826137825784600101613784565b845b63ffffffff8086166000908152602083905260408082208684168352908220549394509268010000000000000000900490911690036137ef576040517f6a118cfc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b63ffffffff808416600090815260208490526040812054600160601b900490911690036138435763ffffffff928316600090815260208390526040902054680100000000000000009004909216916137f0565b63ffffffff80841660009081526020848152604091829020825160c081018452905480851682526401000000008104851692820192909252680100000000000000008204841692810192909252600160601b8104909216606082015267ffffffffffffffff600160801b830481166080830152600160c01b90920490911660a08201525b8363ffffffff166001146139bb5760408082015163ffffffff9081166000908152602086815290839020835160c081018552905480841682526401000000008104841692820192909252680100000000000000008204831693810193909352600160601b8104909116606083015267ffffffffffffffff600160801b820481166080840152600160c01b9091041660a0820152856139835760a0810151835467ffffffffffffffff918216600160c01b909104909116116139a3565b60a0810151835467ffffffffffffffff918216600160c01b909104909116105b156139ae57506139bb565b60409091015193506138c7565b63ffffffff841615613aa457846139f15760a0810151825467ffffffffffffffff918216600160c01b9091049091161115613a12565b60a0810151825467ffffffffffffffff918216600160c01b90910490911610155b613aa45760209081015163ffffffff8082166000908152858452604090819020815160c081018352905480841682526401000000008104841695820195909552680100000000000000008504831691810191909152600160601b8404909116606082015267ffffffffffffffff600160801b840481166080830152600160c01b90930490921660a083015293506139bb565b50805467ffffffff000000001980821664010000000063ffffffff968716818102928317865560009081526020969096526040808720547fffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffff9095166bffffffff00000000000000001993841617680100000000000000009586900489168602178087558290048816875280872080549093169988168086029a909a17909255935492909204909416835290912080549092169302929092179091555050565b60008215613b915781613b77600185614d2c565b613b819190614c53565b613b8c906001614ba7565b610aea565b50600092915050565b60018263ffffffff1611613bda576040517f03d2053e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081613bea5783600101613bec565b835b63ffffffff808516600090815260208390526040812054929350600160601b909204169003613c47576040517fb62f096e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff9283166000908152602091909152604080822080546fffffffff000000000000000000000000191690819055640100000000808204861680855283852080546bffffffff000000000000000019166801000000000000000094859004909816938402979097179096559083529120805467ffffffff00000000191693909102929092179091555050565b604080516101e08101825260008082526020820181905291810182905260608181018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201839052610160820183905261018082018390526101a082018390526101c08201819052829182919060008a613d62576002613d65565b60035b608083018a905260008080526020829052604090205468010000000000000000900463ffffffff168352891561016084015290505b816000015163ffffffff16600114158015613db85750816101600151155b1561430357815163ffffffff1660009081526020829052604090208a8015613ddd57508b5b80613def57508a158015613def57508b155b613e265760808301518154613e2191908e9067ffffffffffffffff600160801b8204811691600160c01b900416610b9b565b613e54565b60808301518154613e5491908e9067ffffffffffffffff600160801b8204811691600160c01b900416611bb6565b151561016087015267ffffffffffffffff1660a086015260e085015260c084018190521580613e85575060e0830151155b15613e905750614303565b8b15613f345782518154600160601b900463ffffffff9081166000908152600660205260408082205460c088015160e08901519251949095169492937fbd8e28ca9aa9ef3945b1e218ce096cb31c1e6ed750c5d1dea41832b27c208ed293613f27938f936001600160a01b0316926001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b60405180910390a3613fd1565b82518154600160601b900463ffffffff9081166000908152600660205260408082205460c088015160e08901519251939594909416937fbd8e28ca9aa9ef3945b1e218ce096cb31c1e6ed750c5d1dea41832b27c208ed293613fc8936001600160a01b03909316928f92916001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b60405180910390a35b8260c0015183604001818151613fe79190614ba7565b90525060e0830151606084018051614000908390614ba7565b9052506101a083015161018084015163ffffffff91821691160361413f576101a083015160049063ffffffff1615614046576101a0840151614043906002614fa8565b90505b60008163ffffffff1667ffffffffffffffff811115614067576140676144a8565b6040519080825280602002602001820160405280156140b257816020015b60408051606081018252600080825260208083018290529282015282526000199092019101816140855790505b50905060005b856101a0015163ffffffff168163ffffffff16101561412b57856101c001518163ffffffff16815181106140ee576140ee614fc8565b6020026020010151828263ffffffff168151811061410e5761410e614fc8565b6020908102919091010152614124600182614cba565b90506140b8565b506101c085015263ffffffff166101a08401525b604080516060810182528254600160601b900463ffffffff16600090815260066020908152929020546001600160a01b031681529081018d614185578460e0015161418b565b8460c001515b815282546001908116146020909101526101c084015161018085018051906141b282614fde565b63ffffffff1663ffffffff1681525063ffffffff16815181106141d7576141d7614fc8565b602090810291909101015260a0830151815467ffffffffffffffff918216600160801b9091049091160361422957600161014084015280546fffffffff0000000000000000000000001916815561427d565b60a083015181548290601090614251908490600160801b900467ffffffffffffffff16615001565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555050614303565b805468010000000000000000900463ffffffff168352610160830151156142a45750614303565b8b80156142ae57508a5b806142c057508b1580156142c057508a155b156142e3578260c00151836080018181516142db9190614d2c565b9052506142fd565b8260e00151836080018181516142f99190614d2c565b9052505b50613d9a565b8161014001511561436357815163ffffffff908116600090815260208390526040808220805467ffffffff00000000191690558451828052912080549190921668010000000000000000026bffffffff0000000000000000199091161790555b81610160015161439f576040517f923dee0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8980156143ce57508a80156143b75750878260600151105b806143ce57508a1580156143ce5750878260400151105b15614405576040517fde5dbbfa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8915801561443557508a801561441e5750878260400151115b8061443557508a1580156144355750878260600151115b1561446c576040517f3a4b028c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50604081015160608201516101808301516101c090930151919c909b50919950975095505050505050565b80151581146144a557600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff811182821017156144e1576144e16144a8565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715614510576145106144a8565b604052919050565b600082601f83011261452957600080fd5b813567ffffffffffffffff811115614543576145436144a8565b6145566020601f19601f840116016144e7565b81815284602083860101111561456b57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561459d57600080fd5b8335925060208401356145af81614497565b9150604084013567ffffffffffffffff8111156145cb57600080fd5b6145d786828701614518565b9150509250925092565b63ffffffff811681146144a557600080fd5b60006020828403121561460557600080fd5b81356125b7816145e1565b803567ffffffffffffffff8116811461462857600080fd5b919050565b6000806040838503121561464057600080fd5b61464983614610565b9150602083013561465981614497565b809150509250929050565b6001600160a01b03811681146144a557600080fd5b60006020828403121561468b57600080fd5b81356125b781614664565b600080600080600060a086880312156146ae57600080fd5b6146b786614610565b94506146c560208701614610565b93506146d360408701614610565b92506146e160608701614610565b915060808601356146f181614497565b809150509295509295909350565b6000806000806080858703121561471557600080fd5b84359350602085013561472781614497565b925061473560408601614610565b915061474360608601614610565b905092959194509250565b60008060008060006080868803121561476657600080fd5b853561477181614664565b94506020860135935060408601359250606086013567ffffffffffffffff8082111561479c57600080fd5b818801915088601f8301126147b057600080fd5b8135818111156147bf57600080fd5b8960208285010111156147d157600080fd5b9699959850939650602001949392505050565b600080600080600080600060e0888a0312156147ff57600080fd5b61480888614610565b965061481660208901614610565b9550604088013561482681614497565b9450606088013561483681614664565b93506080880135614846816145e1565b925060a08801356004811061485a57600080fd5b915060c088013567ffffffffffffffff81111561487657600080fd5b6148828a828b01614518565b91505092959891949750929550565b600080604083850312156148a457600080fd5b82359150602083013561465981614497565b600080604083850312156148c957600080fd5b82356148d4816145e1565b9150602083013561465981614664565b6000806000606084860312156148f957600080fd5b8335614904816145e1565b9250602084013561491481614497565b91506040840135614924816145e1565b809150509250925092565b600081518084526020808501945080840160005b838110156149685781516001600160a01b031687529582019590820190600101614943565b509495945050505050565b600081518084526020808501945080840160005b8381101561496857815187529582019590820190600101614987565b602080825282511515828201528281015160a06040840152805160c0840181905260009291820190839060e08601905b808310156149f957835163ffffffff1682529284019260019290920191908401906149d3565b5060408701519350601f19925082868203016060870152614a1a818561492f565b93505050606085015181858403016080860152614a378382614973565b9250506080850151818584030160a0860152614a538382614973565b9695505050505050565b60008060408385031215614a7057600080fd5b8235614a7b81614497565b91506020830135614659816145e1565b60008060008060008060c08789031215614aa457600080fd5b8635614aaf81614497565b95506020870135614abf81614497565b945060408701359350606087013592506080870135614add81614664565b915060a087013567ffffffffffffffff811115614af957600080fd5b614b0589828a01614518565b9150509295509295509295565b600060208284031215614b2457600080fd5b5051919050565b838152600060206001600160a01b0385168184015260606040840152835180606085015260005b81811015614b6e57858101830151858201608001528201614b52565b506000608082860101526080601f19601f83011685010192505050949350505050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610aed57610aed614b91565b600060208284031215614bcc57600080fd5b81516125b7816145e1565b67ffffffffffffffff818116838216028082169190828114614bfb57614bfb614b91565b505092915050565b6001600160801b03818116838216028082169190828114614bfb57614bfb614b91565b8082028115828204841417610aed57610aed614b91565b634e487b7160e01b600052601260045260246000fd5b600082614c7057634e487b7160e01b600052601260045260246000fd5b500490565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b634e487b7160e01b600052602160045260246000fd5b63ffffffff818116838216019080821115614cd757614cd7614b91565b5092915050565b67ffffffffffffffff85811682528416602082015282151560408201526080810160048310614d1d57634e487b7160e01b600052602160045260246000fd5b82606083015295945050505050565b81810381811115610aed57610aed614b91565b805161462881614497565b600067ffffffffffffffff821115614d6457614d646144a8565b5060051b60200190565b600082601f830112614d7f57600080fd5b81516020614d94614d8f83614d4a565b6144e7565b82815260059290921b84018101918181019086841115614db357600080fd5b8286015b84811015614dd7578051614dca816145e1565b8352918301918301614db7565b509695505050505050565b600082601f830112614df357600080fd5b81516020614e03614d8f83614d4a565b82815260059290921b84018101918181019086841115614e2257600080fd5b8286015b84811015614dd7578051614e3981614664565b8352918301918301614e26565b600082601f830112614e5757600080fd5b81516020614e67614d8f83614d4a565b82815260059290921b84018101918181019086841115614e8657600080fd5b8286015b84811015614dd75780518352918301918301614e8a565b600060208284031215614eb357600080fd5b815167ffffffffffffffff80821115614ecb57600080fd5b9083019060a08286031215614edf57600080fd5b614ee76144be565b614ef083614d3f565b8152602083015182811115614f0457600080fd5b614f1087828601614d6e565b602083015250604083015182811115614f2857600080fd5b614f3487828601614de2565b604083015250606083015182811115614f4c57600080fd5b614f5887828601614e46565b606083015250608083015182811115614f7057600080fd5b614f7c87828601614e46565b60808301525095945050505050565b600060208284031215614f9d57600080fd5b81516125b781614497565b63ffffffff818116838216028082169190828114614bfb57614bfb614b91565b634e487b7160e01b600052603260045260246000fd5b600063ffffffff808316818103614ff757614ff7614b91565b6001019392505050565b67ffffffffffffffff828116828216039080821115614cd757614cd7614b9156fea2646970667358221220b9a1b42fb5f18e557db8fdb009909776e8a88fd858ebaef54cfb0e7b2438879f64736f6c63430008120033000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc8000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000001388000000000000000000000000000000000000000000000000000000003b9aca00

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102265760003560e01c80639087f4741161012a578063be374423116100bd578063d2f2b7661161008c578063d50cb88b11610071578063d50cb88b146106b1578063d819e812146106d8578063e4ae2e281461070157600080fd5b8063d2f2b7661461060c578063d4105e5d1461068957600080fd5b8063be374423146105aa578063cd6c78d0146105ba578063d0e76269146105da578063d21220a7146105e557600080fd5b8063a89883a2116100f9578063a89883a214610546578063b2d6d47514610566578063b866365a1461058c578063b90f2a401461059f57600080fd5b80639087f474146104e657806392250a471461050d57806396e7952e14610520578063a29d824c1461053357600080fd5b8063365044a8116101bd578063620a92351161018c5780637f2ac67a116101715780637f2ac67a14610486578063818748bd14610499578063829d600a146104bf57600080fd5b8063620a92351461042e578063679f05791461047357600080fd5b8063365044a81461037757806348e057ed1461039e57806349d79bc4146103cc5780634a9f29601461040757600080fd5b80632a2ef375116101f95780632a2ef375146102fd5780632cea5cd3146103125780632e53eda51461033557806334d441d31461035d57600080fd5b806301c11d961461022b5780630dfe16811461025857806320957ed31461029757806327d7d68e146102d6575b600080fd5b61023a67ffffffffffffffff81565b60405167ffffffffffffffff90911681526020015b60405180910390f35b61027f7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab181565b6040516001600160a01b03909116815260200161024f565b6102be7f000000000000000000000000000000000000000000000000000000003b9aca0081565b6040516001600160801b03909116815260200161024f565b6102be7f000000000000000000000000000000000000000000000000000000e8d4a5100081565b61031061030b366004614588565b61072a565b005b6103256103203660046145f3565b6109d8565b604051901515815260200161024f565b61034861034336600461462d565b610a42565b60405163ffffffff909116815260200161024f565b610365602681565b60405160ff909116815260200161024f565b6102be7f000000000000000000000000000000000000000000000000000000000000006481565b6103be6103ac366004614679565b60056020526000908152604090205481565b60405190815260200161024f565b6103df6103da366004614696565b610af3565b6040805167ffffffffffffffff90931683526001600160801b0390911660208301520161024f565b6102be7f000000000000000000000000000000000000000000000000000000000000271081565b61044161043c3660046146ff565b610b9b565b60405161024f9493929190938452602084019290925267ffffffffffffffff1660408301521515606082015260800190565b61031061048136600461474e565b610dab565b6103486104943660046147e4565b6111c7565b6103486104a7366004614679565b60076020526000908152604090205463ffffffff1681565b61023a7f000000000000000000000000000000000000000000000000000000000000138881565b6103657f000000000000000000000000000000000000000000000000000000000000000081565b61044161051b3660046146ff565b611bb6565b61031061052e366004614891565b611d38565b6103256105413660046148b6565b611f1a565b6103be610554366004614679565b60046020526000908152604090205481565b610348610574366004614679565b60086020526000908152604090205463ffffffff1681565b61032561059a3660046145f3565b612426565b61034863ffffffff81565b6001546103489063ffffffff1681565b6105cd6105c83660046148e4565b612475565b60405161024f91906149a3565b610348637fffffff81565b61027f7f000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc881565b61061f61061a366004614a5d565b6125be565b60405161024f9190600060c08201905063ffffffff80845116835280602085015116602084015280604085015116604084015280606085015116606084015250608083015167ffffffffffffffff80821660808501528060a08601511660a0850152505092915050565b61069c610697366004614a8b565b61269b565b6040805192835260208301919091520161024f565b6102be7f000000000000000000000000000000000000000000000000000000000000000181565b61027f6106e63660046145f3565b6006602052600090815260409020546001600160a01b031681565b61027f61070f3660046145f3565b6009602052600090815260409020546001600160a01b031681565b610732612792565b33600083610760577f000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc8610782565b7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab15b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156107cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f09190614b12565b6040517f727f979c0000000000000000000000000000000000000000000000000000000081529091506001600160a01b0384169063727f979c9061083c90899086908990600401614b2b565b600060405180830381600087803b15801561085657600080fd5b505af115801561086a573d6000803e3d6000fd5b50505050858161087a9190614ba7565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156108be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e29190614b12565b101561091a576040517fe827b48700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8415610953576001600160a01b03831660009081526004602052604081208054889290610948908490614ba7565b909155506109819050565b6001600160a01b0383166000908152600560205260408120805488929061097b908490614ba7565b90915550505b6040805187815286151560208201526001600160a01b038516917ff939ff49cec37eed853259ac7b9b4c0a8c7aacb9feca8467b3d54512ba26429a910160405180910390a25050506109d36001600055565b505050565b60006109e382612426565b610a19576040517f7312861b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5063ffffffff9081166000908152600260205260409020546001600160601b9091049091161190565b6040517fd271c2c20000000000000000000000000000000000000000000000000000000081526002600482015267ffffffffffffffff8316602482015281151560448201526000907343ccc6d2a517a9a0955fba24c73f2202da5af8b39063d271c2c290606401602060405180830381865af4158015610ac6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aea9190614bba565b90505b92915050565b600080828015610b1757508567ffffffffffffffff168467ffffffffffffffff1610155b80610b3f575082158015610b3f57508367ffffffffffffffff168667ffffffffffffffff1610155b15610b8a578467ffffffffffffffff168767ffffffffffffffff161015610b6857869150610b6c565b8491505b81610b778582614bd7565b67ffffffffffffffff1691509150610b91565b5060009050805b9550959350505050565b600080808080610c11896001600160801b037f000000000000000000000000000000000000000000000000000000000000006416610c037f000000000000000000000000000000000000000000000000000000000000000167ffffffffffffffff8b16614c03565b6001600160801b031661280a565b90508715610ca7576001600160801b037f00000000000000000000000000000000000000000000000000000000000000648116907f000000000000000000000000000000000000000000000000000000000000000116610c7b67ffffffffffffffff891684614c26565b610c859190614c26565b610c8f9190614c53565b935088841015610ca757610ca4600182614ba7565b90505b8667ffffffffffffffff16811115610cce57506000905067ffffffffffffffff8616610cd3565b600191505b8092507f00000000000000000000000000000000000000000000000000000000000000646001600160801b03167f00000000000000000000000000000000000000000000000000000000000000016001600160801b03168767ffffffffffffffff168567ffffffffffffffff16610d4a9190614c26565b610d549190614c26565b610d5e9190614c53565b9350610d9d6001600160801b037f000000000000000000000000000000000000000000000000000000e8d4a510001667ffffffffffffffff8516614c26565b945050945094509450949050565b610db3612792565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b0316906370a0823190602401602060405180830381865afa158015610e1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3e9190614b12565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc816906370a0823190602401602060405180830381865afa158015610ea8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ecc9190614b12565b9050600086118015610f065750610f047f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab18888612916565b155b15610f24576040516309e1fb8b60e31b815260040160405180910390fd5b600085118015610f5c5750610f5a7f000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc88887612916565b155b15610f7a576040516309e1fb8b60e31b815260040160405180910390fd5b6040517f8f36f6400000000000000000000000000000000000000000000000000000000081523390638f36f64090610fb89087908790600401614c75565b600060405180830381600087803b158015610fd257600080fd5b505af1158015610fe6573d6000803e3d6000fd5b50506040516370a0823160e01b81523060048201528492507f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b031691506370a0823190602401602060405180830381865afa158015611050573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110749190614b12565b10156110ac576040517fed7735c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516370a0823160e01b815230600482015281907f000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc86001600160a01b0316906370a0823190602401602060405180830381865afa158015611112573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111369190614b12565b101561116e576040517fed7735c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051878152602081018790526001600160a01b0389169133917f0d7d75e01ab95780d3cd1c8ec0dd6c2ce19e3a20427eec8bf53283b6fb8e95f0910160405180910390a350506111c06001600055565b5050505050565b60006111d1612792565b5060015463ffffffff1667ffffffffffffffff881660000361121f576040517fcdf6143100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000646001600160801b03168767ffffffffffffffff16101561128c576040517f807a1e5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000167ffffffffffffffff8816016112ef576040517f6c84672900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083600381111561130357611303614ca4565b14806113205750600183600381111561131e5761131e614ca4565b145b1561141e578063ffffffff168463ffffffff161061136a576040517f6a118cfc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000138867ffffffffffffffff168867ffffffffffffffff1610806113e757506001600160801b037f000000000000000000000000000000000000000000000000000000003b9aca00166113db8989614bd7565b67ffffffffffffffff16105b1561141e576040517fcdf6143100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915263ffffffff8281161061148f576040517f853a5ad000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61149a826001614cba565b6001805463ffffffff191663ffffffff9283161790556040805160c081018252600080825260208201819052818301819052606082015267ffffffffffffffff8c811660808301528b1660a08201529051909250908316906001600160a01b038816907f7206876180a726787edf45582daa9f64c66460c7f389385372099aa4c64343f090611530908d908d908d908b90614cde565b60405180910390a360008060008061154a85878c8e612ae7565b92965090945092509050600288600381111561156857611568614ca4565b14801561158357506000856080015167ffffffffffffffff16115b156115ba576040517f917126fd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808960038111156115cf576115cf614ca4565b14806115ec575060018960038111156115ea576115ea614ca4565b145b801561160657506000866080015167ffffffffffffffff16115b156116eb578b6116a5577f00000000000000000000000000000000000000000000000000000000000000646001600160801b03167f00000000000000000000000000000000000000000000000000000000000000016001600160801b03168760a0015167ffffffffffffffff16886080015167ffffffffffffffff1661168c9190614c26565b6116969190614c26565b6116a09190614c53565b6116e8565b7f000000000000000000000000000000000000000000000000000000e8d4a510006001600160801b0316866080015167ffffffffffffffff166116e89190614c26565b90505b60008511806116fa5750600084115b806117165750600089600381111561171457611714614ca4565b145b806117325750600189600381111561173057611730614ca4565b145b156117a8576040805161012081019091528c151581526117a8906020810160018c600381111561176457611764614ca4565b14151581526020018d6001600160a01b031681526020018781526020018681526020018381526020018563ffffffff1681526020018481526020018a815250613194565b8015611b9b576001600160a01b038b1660009081526007602052604081205463ffffffff166060880181905290036118455763ffffffff8716606087018190526001600160a01b038c166000818152600760209081526040808320805463ffffffff191686179055938252600690529190912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690911790555b336001600160a01b038c1614611929573360009081526008602052604081205463ffffffff16808852900361191b57637fffffff63ffffffff8816106118b7576040517fd1cd82ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff808816808852336000818152600860209081526040808320805463ffffffff19169095179094558a5190941681526009909352912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690911790555b855160011b63fffffffe1686525b600189600381111561193d5761193d614ca4565b0361195057855160011763ffffffff1686525b8b15611a7a5763ffffffff8088166000908152600260208181526040928390208a518154928c0151948c015160608d015160808e015160a08f015167ffffffffffffffff908116600160c01b0277ffffffffffffffffffffffffffffffffffffffffffffffff91909216600160801b02166001600160801b03928a16600160601b026fffffffff00000000000000000000000019948b166801000000000000000002949094167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998b16640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909816958b169590951796909617979097169290921717169190911792909217909155611a759189908f908e9061377216565b611b9b565b63ffffffff80881660009081526003602090815260409182902089518154928b0151938b015160608c015160808d015160a08e015167ffffffffffffffff908116600160c01b0277ffffffffffffffffffffffffffffffffffffffffffffffff91909216600160801b02166001600160801b03928916600160601b026fffffffff00000000000000000000000019948a166801000000000000000002949094167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff988a16640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909816958a1695909517969096179690961692909217171691909117919091179055611b9b9060029089908f908e9061377216565b505050505050611bab6001600055565b979650505050505050565b60008060008060008715611bfe57611bf76001600160801b037f000000000000000000000000000000000000000000000000000000e8d4a51000168a614c53565b9050611c34565b611c31897f000000000000000000000000000000000000000000000000000000e8d4a510006001600160801b0316613b63565b90505b8667ffffffffffffffff16811115611c5b57506000905067ffffffffffffffff8616611c60565b600191505b915081611ca06001600160801b037f000000000000000000000000000000000000000000000000000000e8d4a510001667ffffffffffffffff8316614c26565b94507f00000000000000000000000000000000000000000000000000000000000000646001600160801b03167f00000000000000000000000000000000000000000000000000000000000000016001600160801b03168767ffffffffffffffff168567ffffffffffffffff16611d169190614c26565b611d209190614c26565b611d2a9190614c53565b935050945094509450949050565b611d40612792565b33600082611d66576001600160a01b038216600090815260056020526040902054611d80565b6001600160a01b0382166000908152600460205260409020545b9050600084118015611d925750808411155b15611ed8578215611e18576001600160a01b03821660009081526004602052604081208054869290611dc5908490614d2c565b90915550611df690507f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab18386612916565b611e13576040516309e1fb8b60e31b815260040160405180910390fd5b611e8e565b6001600160a01b03821660009081526005602052604081208054869290611e40908490614d2c565b90915550611e7190507f000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc88386612916565b611e8e576040516309e1fb8b60e31b815260040160405180910390fd5b6040805185815284151560208201526001600160a01b038416917fccd5b8d697ca09c88b66c7bd627d6bb0c9a161861c693df7fdb380d758b2257a910160405180910390a2611f0a565b6040517f9db10d0100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050611f166001600055565b5050565b6000611f24612792565b611f2d83612426565b611f395750600061241c565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905290611f74856109d8565b905080156120085763ffffffff808616600090815260026020908152604091829020825160c081018452905480851682526401000000008104851692820192909252680100000000000000008204841692810192909252600160601b8104909216606082015267ffffffffffffffff600160801b830481166080830152600160c01b90920490911660a08201529150612090565b63ffffffff808616600090815260036020908152604091829020825160c081018452905480851682526401000000008104851692820192909252680100000000000000008204841692810192909252600160601b8104909216606082015267ffffffffffffffff600160801b830481166080830152600160c01b90920490911660a082015291505b606082015163ffffffff1660009081526006602052604090205482516001600160a01b039091169060011c637fffffff168181156120e9575063ffffffff81166000908152600960205260409020546001600160a01b03165b826001600160a01b0316876001600160a01b03161415806121275750336001600160a01b038216148015906121275750336001600160a01b03841614155b1561215e576040517fa934f3c200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405163ffffffff8916907ff584155be07e1a74cb2bc291299df861c09f00cbc773d1509595ed4ff938398f90600090a283156122af5760007f000000000000000000000000000000000000000000000000000000e8d4a510006001600160801b0316866080015167ffffffffffffffff166121da9190614c26565b86519091506000906001168103612219576122167f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab18684612916565b90505b8061229c576001600160a01b03851660009081526004602052604081208054849290612246908490614ba7565b9091555050865160011660000361229c5760408051838152600160208201526001600160a01b038716917ff939ff49cec37eed853259ac7b9b4c0a8c7aacb9feca8467b3d54512ba26429a910160405180910390a25b6122a860028b88613b9a565b5050612412565b60007f00000000000000000000000000000000000000000000000000000000000000646001600160801b03167f00000000000000000000000000000000000000000000000000000000000000016001600160801b03168760a0015167ffffffffffffffff16886080015167ffffffffffffffff1661232d9190614c26565b6123379190614c26565b6123419190614c53565b865190915060009060011681036123805761237d7f000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc88684612916565b90505b80612403576001600160a01b038516600090815260056020526040812080548492906123ad908490614ba7565b909155505086516001166000036124035760408051838152600060208201526001600160a01b038716917ff939ff49cec37eed853259ac7b9b4c0a8c7aacb9feca8467b3d54512ba26429a910160405180910390a25b61240f60028b88613b9a565b50505b6001955050505050505b610aed6001600055565b63ffffffff8082166000908152600260205260408120549091600160601b90910416151580610aed57505063ffffffff908116600090815260036020526040902054600160601b900416151590565b6124a96040518060a00160405280600015158152602001606081526020016060815260200160608152602001606081525090565b6040517f91bf05e50000000000000000000000000000000000000000000000000000000081526002600482015263ffffffff8086166024830152841515604483015283166064820152600660848201526001600160801b037f000000000000000000000000000000000000000000000000000000e8d4a51000811660a48301527f00000000000000000000000000000000000000000000000000000000000027101660c48201527343ccc6d2a517a9a0955fba24c73f2202da5af8b3906391bf05e59060e401600060405180830381865af415801561258c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125b49190810190614ea1565b90505b9392505050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091528261260f5763ffffffff82166000908152600360205260409020612625565b63ffffffff821660009081526002602052604090205b6040805160c081018252915463ffffffff8082168452640100000000820481166020850152680100000000000000008204811692840192909252600160601b8104909116606083015267ffffffffffffffff600160801b820481166080840152600160c01b9091041660a0820152905092915050565b6000806126a6612792565b6000806000806126b98c8c8c8c8c613cd6565b935093509350935061271e6040518061012001604052808e151581526020016000151581526020018a6001600160a01b03168152602001868152602001858152602001600081526020018463ffffffff16815260200183815260200189815250613194565b604080518c151581528d15156020820152908101859052606081018490526001600160a01b0389169033907fd1a5d53e1dd2f18ece2c41d1516ce4335c4022b00735378ec82a4eb657724bb29060800160405180910390a3509193509150506127876001600055565b965096945050505050565b600260005403612803576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b6002600055565b60008080600019858709858702925082811083820303915050806000036128445783828161283a5761283a614c3d565b04925050506125b7565b8084116128ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f77000000000000000000000060448201526064016127fa565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6040516370a0823160e01b815230600482015260009081906001600160a01b038616906370a0823190602401602060405180830381865afa15801561295f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129839190614b12565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526024820186905291925060009187169063a9059cbb906044016020604051808303816000875af1925050508015612a0d575060408051601f3d908101601f19168201909252612a0a91810190614f8b565b60015b612a1957506000612a1c565b90505b600081612a2a576000612a2c565b845b6040516370a0823160e01b8152306004820152909150839082906001600160a01b038a16906370a0823190602401602060405180830381865afa158015612a77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a9b9190614b12565b612aa59190614ba7565b1015612add576040517f4ad2d0b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5095945050505050565b604080516101e08101825260008082526020820181905291810182905260608181018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201839052610160820183905261018082018390526101a082018390526101c082018190528291829190600086612b73576002612b76565b60035b60008080526020829052604090205468010000000000000000900463ffffffff16835290505b816000015163ffffffff16600114158015612bc5575060008a6080015167ffffffffffffffff16115b1561310a57815163ffffffff9081166000908152602083815260408083208054600160601b81049095168452600683529220546001600160a01b03169085015260808c015160a08d01519192612c37929067ffffffffffffffff600160801b8204811691600160c01b9004168c610af3565b6001600160801b031661012085015267ffffffffffffffff1661010084018190521580612c7057506101208301516001600160801b0316155b15612c7b575061310a565b7f000000000000000000000000000000000000000000000000000000e8d4a510006001600160801b031683610100015167ffffffffffffffff16612cbf9190614c26565b60c08401526101208301516001600160801b037f0000000000000000000000000000000000000000000000000000000000000064811691612d24917f000000000000000000000000000000000000000000000000000000000000000181169116614c26565b612d2e9190614c53565b60e08401528715612dbd57826000015163ffffffff168a63ffffffff167fbd8e28ca9aa9ef3945b1e218ce096cb31c1e6ed750c5d1dea41832b27c208ed28b86602001518760c001518860e00151604051612db094939291906001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b60405180910390a3612e2f565b825160208085015160c086015160e0870151604080516001600160a01b039485168152938f169484019490945292820152606081019190915263ffffffff808d169216907fbd8e28ca9aa9ef3945b1e218ce096cb31c1e6ed750c5d1dea41832b27c208ed29060800160405180910390a35b8260c001518360400151612e439190614ba7565b604084015260e08301516060840151612e5c9190614ba7565b60608401526101a083015161018084015163ffffffff918216911603612f9d576101a083015160049063ffffffff1615612ea4576101a0840151612ea1906002614fa8565b90505b60008163ffffffff1667ffffffffffffffff811115612ec557612ec56144a8565b604051908082528060200260200182016040528015612f1057816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181612ee35790505b50905060005b856101a0015163ffffffff168163ffffffff161015612f8957856101c001518163ffffffff1681518110612f4c57612f4c614fc8565b6020026020010151828263ffffffff1681518110612f6c57612f6c614fc8565b6020908102919091010152612f82600182614cba565b9050612f16565b506101c085015263ffffffff166101a08401525b604051806060016040528084602001516001600160a01b0316815260200189612fca578460e00151612fd0565b8460c001515b815282546001908116146020909101526101c08401516101808501805190612ff782614fde565b63ffffffff1663ffffffff1681525063ffffffff168151811061301c5761301c614fc8565b60200260200101819052508261010001518b6080015161303c9190615001565b67ffffffffffffffff90811660808d01526101008401518254908216600160801b9091049091160361308c57600161014084015280546fffffffff000000000000000000000000191681556130f0565b61010083015181546130af9190600160801b900467ffffffffffffffff16615001565b815467ffffffffffffffff91909116600160801b027fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff90911617905561310a565b5468010000000000000000900463ffffffff168252612b9c565b8161014001511561316a57815163ffffffff908116600090815260208390526040808220805467ffffffff00000000191690558451828052912080549190921668010000000000000000026bffffffff0000000000000000199091161790555b50604081015160608201516101808301516101c090930151919b909a509198509650945050505050565b80516000906131c3577f000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc86131e5565b7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab15b905060008260000151613218577f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab161323a565b7f000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc85b905060008360a00151846000015161325657846080015161325c565b84606001515b6132669190614ba7565b90506000846000015161327d578460600151613283565b84608001515b9050801561332b578460200151156132ff578451156132d3576040808601516001600160a01b03166000908152600560205290812080548392906132c8908490614ba7565b9091555061332b9050565b6040808601516001600160a01b03166000908152600460205290812080548392906132c8908490614ba7565b61330e83866040015183612916565b61332b576040516309e1fb8b60e31b815260040160405180910390fd5b846020015115613417578451156133af5733600090815260046020526040902054821115613385576040517fedb4840900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260046020526040812080548492906133a4908490614d2c565b909155506135a99050565b336000908152600560205260409020548211156133f8576040517fedb4840900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260056020526040812080548492906133a4908490614d2c565b6040516370a0823160e01b81523060048201526000906001600160a01b038616906370a0823190602401602060405180830381865afa15801561345e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134829190614b12565b6101008701516040517f727f979c000000000000000000000000000000000000000000000000000000008152919250339163727f979c916134c99187918a91600401614b2b565b600060405180830381600087803b1580156134e357600080fd5b505af11580156134f7573d6000803e3d6000fd5b5050505082816135079190614ba7565b6040516370a0823160e01b81523060048201526001600160a01b038716906370a0823190602401602060405180830381865afa15801561354b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061356f9190614b12565b10156135a7576040517f07bb680200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b60005b8560c0015163ffffffff168163ffffffff16101561376a5760008660e001518263ffffffff16815181106135e2576135e2614fc8565b60200260200101519050806040015115613668578651156136385760208082015182516001600160a01b0316600090815260049092526040822080549192909161362d908490614ba7565b909155506137599050565b60208082015182516001600160a01b0316600090815260059092526040822080549192909161362d908490614ba7565b600061367d8783600001518460200151612916565b905080613757578751156136c65760208083015183516001600160a01b031660009081526004909252604082208054919290916136bb908490614ba7565b909155506136fc9050565b60208083015183516001600160a01b031660009081526005909252604082208054919290916136f6908490614ba7565b90915550505b81600001516001600160a01b03167ff939ff49cec37eed853259ac7b9b4c0a8c7aacb9feca8467b3d54512ba26429a83602001518a6000015160405161374e9291909182521515602082015260400190565b60405180910390a25b505b5061376381614fde565b90506135ac565b505050505050565b6000826137825784600101613784565b845b63ffffffff8086166000908152602083905260408082208684168352908220549394509268010000000000000000900490911690036137ef576040517f6a118cfc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b63ffffffff808416600090815260208490526040812054600160601b900490911690036138435763ffffffff928316600090815260208390526040902054680100000000000000009004909216916137f0565b63ffffffff80841660009081526020848152604091829020825160c081018452905480851682526401000000008104851692820192909252680100000000000000008204841692810192909252600160601b8104909216606082015267ffffffffffffffff600160801b830481166080830152600160c01b90920490911660a08201525b8363ffffffff166001146139bb5760408082015163ffffffff9081166000908152602086815290839020835160c081018552905480841682526401000000008104841692820192909252680100000000000000008204831693810193909352600160601b8104909116606083015267ffffffffffffffff600160801b820481166080840152600160c01b9091041660a0820152856139835760a0810151835467ffffffffffffffff918216600160c01b909104909116116139a3565b60a0810151835467ffffffffffffffff918216600160c01b909104909116105b156139ae57506139bb565b60409091015193506138c7565b63ffffffff841615613aa457846139f15760a0810151825467ffffffffffffffff918216600160c01b9091049091161115613a12565b60a0810151825467ffffffffffffffff918216600160c01b90910490911610155b613aa45760209081015163ffffffff8082166000908152858452604090819020815160c081018352905480841682526401000000008104841695820195909552680100000000000000008504831691810191909152600160601b8404909116606082015267ffffffffffffffff600160801b840481166080830152600160c01b90930490921660a083015293506139bb565b50805467ffffffff000000001980821664010000000063ffffffff968716818102928317865560009081526020969096526040808720547fffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffff9095166bffffffff00000000000000001993841617680100000000000000009586900489168602178087558290048816875280872080549093169988168086029a909a17909255935492909204909416835290912080549092169302929092179091555050565b60008215613b915781613b77600185614d2c565b613b819190614c53565b613b8c906001614ba7565b610aea565b50600092915050565b60018263ffffffff1611613bda576040517f03d2053e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081613bea5783600101613bec565b835b63ffffffff808516600090815260208390526040812054929350600160601b909204169003613c47576040517fb62f096e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff9283166000908152602091909152604080822080546fffffffff000000000000000000000000191690819055640100000000808204861680855283852080546bffffffff000000000000000019166801000000000000000094859004909816938402979097179096559083529120805467ffffffff00000000191693909102929092179091555050565b604080516101e08101825260008082526020820181905291810182905260608181018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201839052610160820183905261018082018390526101a082018390526101c08201819052829182919060008a613d62576002613d65565b60035b608083018a905260008080526020829052604090205468010000000000000000900463ffffffff168352891561016084015290505b816000015163ffffffff16600114158015613db85750816101600151155b1561430357815163ffffffff1660009081526020829052604090208a8015613ddd57508b5b80613def57508a158015613def57508b155b613e265760808301518154613e2191908e9067ffffffffffffffff600160801b8204811691600160c01b900416610b9b565b613e54565b60808301518154613e5491908e9067ffffffffffffffff600160801b8204811691600160c01b900416611bb6565b151561016087015267ffffffffffffffff1660a086015260e085015260c084018190521580613e85575060e0830151155b15613e905750614303565b8b15613f345782518154600160601b900463ffffffff9081166000908152600660205260408082205460c088015160e08901519251949095169492937fbd8e28ca9aa9ef3945b1e218ce096cb31c1e6ed750c5d1dea41832b27c208ed293613f27938f936001600160a01b0316926001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b60405180910390a3613fd1565b82518154600160601b900463ffffffff9081166000908152600660205260408082205460c088015160e08901519251939594909416937fbd8e28ca9aa9ef3945b1e218ce096cb31c1e6ed750c5d1dea41832b27c208ed293613fc8936001600160a01b03909316928f92916001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b60405180910390a35b8260c0015183604001818151613fe79190614ba7565b90525060e0830151606084018051614000908390614ba7565b9052506101a083015161018084015163ffffffff91821691160361413f576101a083015160049063ffffffff1615614046576101a0840151614043906002614fa8565b90505b60008163ffffffff1667ffffffffffffffff811115614067576140676144a8565b6040519080825280602002602001820160405280156140b257816020015b60408051606081018252600080825260208083018290529282015282526000199092019101816140855790505b50905060005b856101a0015163ffffffff168163ffffffff16101561412b57856101c001518163ffffffff16815181106140ee576140ee614fc8565b6020026020010151828263ffffffff168151811061410e5761410e614fc8565b6020908102919091010152614124600182614cba565b90506140b8565b506101c085015263ffffffff166101a08401525b604080516060810182528254600160601b900463ffffffff16600090815260066020908152929020546001600160a01b031681529081018d614185578460e0015161418b565b8460c001515b815282546001908116146020909101526101c084015161018085018051906141b282614fde565b63ffffffff1663ffffffff1681525063ffffffff16815181106141d7576141d7614fc8565b602090810291909101015260a0830151815467ffffffffffffffff918216600160801b9091049091160361422957600161014084015280546fffffffff0000000000000000000000001916815561427d565b60a083015181548290601090614251908490600160801b900467ffffffffffffffff16615001565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555050614303565b805468010000000000000000900463ffffffff168352610160830151156142a45750614303565b8b80156142ae57508a5b806142c057508b1580156142c057508a155b156142e3578260c00151836080018181516142db9190614d2c565b9052506142fd565b8260e00151836080018181516142f99190614d2c565b9052505b50613d9a565b8161014001511561436357815163ffffffff908116600090815260208390526040808220805467ffffffff00000000191690558451828052912080549190921668010000000000000000026bffffffff0000000000000000199091161790555b81610160015161439f576040517f923dee0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8980156143ce57508a80156143b75750878260600151105b806143ce57508a1580156143ce5750878260400151105b15614405576040517fde5dbbfa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8915801561443557508a801561441e5750878260400151115b8061443557508a1580156144355750878260600151115b1561446c576040517f3a4b028c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50604081015160608201516101808301516101c090930151919c909b50919950975095505050505050565b80151581146144a557600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff811182821017156144e1576144e16144a8565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715614510576145106144a8565b604052919050565b600082601f83011261452957600080fd5b813567ffffffffffffffff811115614543576145436144a8565b6145566020601f19601f840116016144e7565b81815284602083860101111561456b57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561459d57600080fd5b8335925060208401356145af81614497565b9150604084013567ffffffffffffffff8111156145cb57600080fd5b6145d786828701614518565b9150509250925092565b63ffffffff811681146144a557600080fd5b60006020828403121561460557600080fd5b81356125b7816145e1565b803567ffffffffffffffff8116811461462857600080fd5b919050565b6000806040838503121561464057600080fd5b61464983614610565b9150602083013561465981614497565b809150509250929050565b6001600160a01b03811681146144a557600080fd5b60006020828403121561468b57600080fd5b81356125b781614664565b600080600080600060a086880312156146ae57600080fd5b6146b786614610565b94506146c560208701614610565b93506146d360408701614610565b92506146e160608701614610565b915060808601356146f181614497565b809150509295509295909350565b6000806000806080858703121561471557600080fd5b84359350602085013561472781614497565b925061473560408601614610565b915061474360608601614610565b905092959194509250565b60008060008060006080868803121561476657600080fd5b853561477181614664565b94506020860135935060408601359250606086013567ffffffffffffffff8082111561479c57600080fd5b818801915088601f8301126147b057600080fd5b8135818111156147bf57600080fd5b8960208285010111156147d157600080fd5b9699959850939650602001949392505050565b600080600080600080600060e0888a0312156147ff57600080fd5b61480888614610565b965061481660208901614610565b9550604088013561482681614497565b9450606088013561483681614664565b93506080880135614846816145e1565b925060a08801356004811061485a57600080fd5b915060c088013567ffffffffffffffff81111561487657600080fd5b6148828a828b01614518565b91505092959891949750929550565b600080604083850312156148a457600080fd5b82359150602083013561465981614497565b600080604083850312156148c957600080fd5b82356148d4816145e1565b9150602083013561465981614664565b6000806000606084860312156148f957600080fd5b8335614904816145e1565b9250602084013561491481614497565b91506040840135614924816145e1565b809150509250925092565b600081518084526020808501945080840160005b838110156149685781516001600160a01b031687529582019590820190600101614943565b509495945050505050565b600081518084526020808501945080840160005b8381101561496857815187529582019590820190600101614987565b602080825282511515828201528281015160a06040840152805160c0840181905260009291820190839060e08601905b808310156149f957835163ffffffff1682529284019260019290920191908401906149d3565b5060408701519350601f19925082868203016060870152614a1a818561492f565b93505050606085015181858403016080860152614a378382614973565b9250506080850151818584030160a0860152614a538382614973565b9695505050505050565b60008060408385031215614a7057600080fd5b8235614a7b81614497565b91506020830135614659816145e1565b60008060008060008060c08789031215614aa457600080fd5b8635614aaf81614497565b95506020870135614abf81614497565b945060408701359350606087013592506080870135614add81614664565b915060a087013567ffffffffffffffff811115614af957600080fd5b614b0589828a01614518565b9150509295509295509295565b600060208284031215614b2457600080fd5b5051919050565b838152600060206001600160a01b0385168184015260606040840152835180606085015260005b81811015614b6e57858101830151858201608001528201614b52565b506000608082860101526080601f19601f83011685010192505050949350505050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610aed57610aed614b91565b600060208284031215614bcc57600080fd5b81516125b7816145e1565b67ffffffffffffffff818116838216028082169190828114614bfb57614bfb614b91565b505092915050565b6001600160801b03818116838216028082169190828114614bfb57614bfb614b91565b8082028115828204841417610aed57610aed614b91565b634e487b7160e01b600052601260045260246000fd5b600082614c7057634e487b7160e01b600052601260045260246000fd5b500490565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b634e487b7160e01b600052602160045260246000fd5b63ffffffff818116838216019080821115614cd757614cd7614b91565b5092915050565b67ffffffffffffffff85811682528416602082015282151560408201526080810160048310614d1d57634e487b7160e01b600052602160045260246000fd5b82606083015295945050505050565b81810381811115610aed57610aed614b91565b805161462881614497565b600067ffffffffffffffff821115614d6457614d646144a8565b5060051b60200190565b600082601f830112614d7f57600080fd5b81516020614d94614d8f83614d4a565b6144e7565b82815260059290921b84018101918181019086841115614db357600080fd5b8286015b84811015614dd7578051614dca816145e1565b8352918301918301614db7565b509695505050505050565b600082601f830112614df357600080fd5b81516020614e03614d8f83614d4a565b82815260059290921b84018101918181019086841115614e2257600080fd5b8286015b84811015614dd7578051614e3981614664565b8352918301918301614e26565b600082601f830112614e5757600080fd5b81516020614e67614d8f83614d4a565b82815260059290921b84018101918181019086841115614e8657600080fd5b8286015b84811015614dd75780518352918301918301614e8a565b600060208284031215614eb357600080fd5b815167ffffffffffffffff80821115614ecb57600080fd5b9083019060a08286031215614edf57600080fd5b614ee76144be565b614ef083614d3f565b8152602083015182811115614f0457600080fd5b614f1087828601614d6e565b602083015250604083015182811115614f2857600080fd5b614f3487828601614de2565b604083015250606083015182811115614f4c57600080fd5b614f5887828601614e46565b606083015250608083015182811115614f7057600080fd5b614f7c87828601614e46565b60808301525095945050505050565b600060208284031215614f9d57600080fd5b81516125b781614497565b63ffffffff818116838216028082169190828114614bfb57614bfb614b91565b634e487b7160e01b600052603260045260246000fd5b600063ffffffff808316818103614ff757614ff7614b91565b6001019392505050565b67ffffffffffffffff828116828216039080821115614cd757614cd7614b9156fea2646970667358221220b9a1b42fb5f18e557db8fdb009909776e8a88fd858ebaef54cfb0e7b2438879f64736f6c63430008120033

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

000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc8000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000001388000000000000000000000000000000000000000000000000000000003b9aca00

-----Decoded View---------------
Arg [0] : _orderBookId (uint8): 0
Arg [1] : _token0Address (address): 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1
Arg [2] : _token1Address (address): 0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8
Arg [3] : _logSizeTick (uint8): 12
Arg [4] : _logPriceTick (uint8): 4
Arg [5] : _minToken0BaseAmount (uint64): 5000
Arg [6] : _minToken1BaseAmount (uint128): 1000000000

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [1] : 00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1
Arg [2] : 000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc8
Arg [3] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [5] : 0000000000000000000000000000000000000000000000000000000000001388
Arg [6] : 000000000000000000000000000000000000000000000000000000003b9aca00


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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