Contract 0x935FB1838974D09d33cDcec0189D0e99f77cC92f

 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0xf4c500d9e79dae22bc2a23cf77a9ff3f21866666ee0a5b16785151faa168ff5a0x61016060550460142023-01-24 2:09:36430 days 8 hrs ago0xc1e5e997ea88eb0aa18af4cede444be8c8e1e2c1 IN  Create: Auction0 ETH0.00293699 0.1
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xb2a8b6b327890a69ceca16fad0a72a9a7cce8d586310c49684f69ddb4df36554713069582023-03-19 4:01:50376 days 6 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0xcff53309a10117c76cf9c6f04f0be580d46c3ad37cd6070f821f911900fdba29708030642023-03-17 16:31:43377 days 17 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0xcff53309a10117c76cf9c6f04f0be580d46c3ad37cd6070f821f911900fdba29708030642023-03-17 16:31:43377 days 17 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0xcadc9cb2029ed12f72c97c149318739017ed537b41f03ccb125e20fcc7955cfd708030522023-03-17 16:31:40377 days 17 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0xf0246e0e90cef0c0b8b61b71a6a978dacfdc82a61f26d5b20e6576b54d084631707886772023-03-17 15:31:35377 days 18 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0x0cfa8f96cd3c5c32a78d242aecdae33c4659581c3d9fdfaff084892a73dfd164707622152023-03-17 13:42:23377 days 20 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0x8bc68e9c66e46e938083e6665064903a06eeab46ca7094802b5172f8d6544512703393032023-03-16 8:00:35379 days 2 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0xa4983d9f3216b56931e7de88d63a3f27facdcf015e5aa705303eb303e0ab8c3f695130882023-03-13 18:18:43381 days 15 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0xeec656a5508d18c4a787bce0e1756f759a6c19b0c53daaa30cfe67b9b16cc3d9689650912023-03-11 22:33:58383 days 11 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0xc41dbc77ea9d00924119b8fa921df3d0cefbdd2284457ff0800ae14beffef94d685847612023-03-10 16:31:42384 days 17 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0xc41dbc77ea9d00924119b8fa921df3d0cefbdd2284457ff0800ae14beffef94d685847612023-03-10 16:31:42384 days 17 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0x7a5a6e53a3c18aa5d8312bd521551f6071c2c7e176edb9fc4990bbc4082a2519685807562023-03-10 16:14:13384 days 18 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0x2a3051107873531d912ad06d6158efab8e026af832fe02c41c3a9999efce05e6685806532023-03-10 16:13:46384 days 18 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0xf2dfcd4bae2c2207541f735bacbfc6358e27abf764ced1f0980ac46df01b2d5c685777332023-03-10 16:00:35384 days 18 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0x3c9b3b3f45bf3c996fbe130960c8d2d14d54fcedefba633ec5e98e6689b5e27c685775332023-03-10 15:59:41384 days 18 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0xce8121b4b71a318fa2b5f000b2c5905f6bbf5c2ac2d1fc10fdade9c3b20476fd685712252023-03-10 15:31:41384 days 18 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0xeda5c3e75d063e7654a116b6e0c9d61c952ace21c23d525d328dbe48dee410ac685711872023-03-10 15:31:35384 days 18 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0x92ae761fadaa52a0328a37d8a3c5328300d550c684a9c16c5f383ed2331ad4fb685710502023-03-10 15:30:56384 days 18 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0xf83d28c77ad4a904b89f5600bf9c44b277c9cf6ec23fb0a6e3ad66531d488e63685707042023-03-10 15:29:24384 days 18 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0xff25950a3bce99fe87e89dc76efb93e6ae388b2bc3e5630991982e81825b347f681477782023-03-09 8:00:38386 days 2 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0xa57ec96d6d2b360a365129319d42f9179af90eba6d427e3215cdea3b599f2b1b664304342023-03-03 16:31:38391 days 17 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0xa57ec96d6d2b360a365129319d42f9179af90eba6d427e3215cdea3b599f2b1b664304342023-03-03 16:31:38391 days 17 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0x440e12ee2f318101086cc8479c2654fa5546aaf8df9f100c1337c38044aa7bb7664246282023-03-03 16:05:58391 days 18 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0x6548807b83c1df3d1e59db22fe8e84bd31b5e6131403bdabfbe79e4c41558d1c664245532023-03-03 16:05:39391 days 18 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
0x0845d83d3a144b1603f9be6c360b74153ed2fc3c4d8d6bb71390faa9f6ee224a664237692023-03-03 16:02:19391 days 18 hrs ago 0xb28b26c662e1cc1373c43ad3d06c08abc17229ab 0x935fb1838974d09d33cdcec0189d0e99f77cc92f0 ETH
[ Download CSV Export 
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
Auction

Compiler Version
v0.8.12+commit.f00d7308

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 46 : Auction.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@solidstate/contracts/introspection/ERC165Storage.sol";
import "@solidstate/contracts/utils/Multicall.sol";
import "@solidstate/contracts/utils/ReentrancyGuard.sol";

import "./AuctionInternal.sol";
import "./IAuction.sol";

/**
 * @title Knox Dutch Auction Contract
 * @dev deployed standalone and referenced by AuctionProxy
 */

contract Auction is AuctionInternal, IAuction, Multicall, ReentrancyGuard {
    using ABDKMath64x64 for int128;
    using AuctionStorage for AuctionStorage.Layout;
    using EnumerableSet for EnumerableSet.UintSet;
    using ERC165Storage for ERC165Storage.Layout;
    using OrderBook for OrderBook.Index;
    using SafeERC20 for IERC20;

    int128 private constant ONE_64x64 = 0x10000000000000000;

    constructor(
        bool isCall,
        address pool,
        address vault,
        address weth
    ) AuctionInternal(isCall, pool, vault, weth) {}

    /************************************************
     *  ADMIN
     ***********************************************/

    /**
     * @inheritdoc IAuction
     */
    function setDeltaOffset64x64(int128 newDeltaOffset64x64)
        external
        onlyOwner
    {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        require(newDeltaOffset64x64 > 0, "delta <= 0");
        require(newDeltaOffset64x64 < ONE_64x64, "delta > 1");

        emit DeltaOffsetSet(
            l.deltaOffset64x64,
            newDeltaOffset64x64,
            msg.sender
        );

        l.deltaOffset64x64 = newDeltaOffset64x64;
    }

    /**
     * @inheritdoc IAuction
     */
    function setExchangeHelper(address newExchangeHelper) external onlyOwner {
        AuctionStorage.Layout storage l = AuctionStorage.layout();

        require(newExchangeHelper != address(0), "address not provided");
        require(
            newExchangeHelper != address(l.Exchange),
            "new address equals old"
        );

        emit ExchangeHelperSet(
            address(l.Exchange),
            newExchangeHelper,
            msg.sender
        );

        l.Exchange = IExchangeHelper(newExchangeHelper);
    }

    /**
     * @inheritdoc IAuction
     */
    function setMinSize(uint256 newMinSize) external onlyOwner {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        require(newMinSize > 0, "value exceeds minimum");
        emit MinSizeSet(l.minSize, newMinSize, msg.sender);
        l.minSize = newMinSize;
    }

    /**
     * @inheritdoc IAuction
     */
    function setPricer(address newPricer) external onlyOwner {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        require(newPricer != address(0), "address not provided");
        require(newPricer != address(l.Pricer), "new address equals old");
        emit PricerSet(address(l.Pricer), newPricer, msg.sender);
        l.Pricer = IPricer(newPricer);
    }

    /************************************************
     *  INITIALIZE AUCTION
     ***********************************************/

    /**
     * @inheritdoc IAuction
     */
    function initialize(AuctionStorage.InitAuction memory initAuction)
        external
        onlyVault
    {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        AuctionStorage.Auction storage auction = l.auctions[initAuction.epoch];

        require(
            auction.status == AuctionStorage.Status.UNINITIALIZED,
            "status != uninitialized"
        );

        if (
            initAuction.startTime >= initAuction.endTime ||
            block.timestamp > initAuction.startTime ||
            block.timestamp > initAuction.expiry ||
            initAuction.strike64x64 <= 0 ||
            initAuction.longTokenId <= 0
        ) {
            // the auction is cancelled if the start time is greater than or equal to
            // the end time, the current time is greater than the start time, or the
            // option parameters are invalid
            _cancel(l.auctions[initAuction.epoch], initAuction.epoch);
        } else {
            auction.expiry = initAuction.expiry;
            auction.strike64x64 = initAuction.strike64x64;
            auction.startTime = initAuction.startTime;
            auction.endTime = initAuction.endTime;
            auction.longTokenId = initAuction.longTokenId;

            _updateStatus(
                auction,
                AuctionStorage.Status.INITIALIZED,
                initAuction.epoch
            );
        }
    }

    /**
     * @inheritdoc IAuction
     */
    function setAuctionPrices(uint64 epoch) external {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        AuctionStorage.Auction storage auction = l.auctions[epoch];

        require(
            AuctionStorage.Status.INITIALIZED == auction.status,
            "status != initialized"
        );

        require(
            block.timestamp > auction.startTime - 30 minutes,
            "price set too early"
        );

        require(
            auction.minPrice64x64 <= 0 || auction.maxPrice64x64 <= 0,
            "prices are already set"
        );

        if (auction.startTime > block.timestamp) {
            int128 spot64x64;
            int128 timeToMaturity64x64;

            // fetches the spot price of the underlying
            try l.Pricer.latestAnswer64x64() returns (int128 _spot64x64) {
                spot64x64 = _spot64x64;
            } catch Error(string memory message) {
                emit Log(message);
                spot64x64 = 0;
            }

            // fetches the time to maturity of the option
            try l.Pricer.getTimeToMaturity64x64(auction.expiry) returns (
                int128 _timeToMaturity64x64
            ) {
                timeToMaturity64x64 = _timeToMaturity64x64;
            } catch Error(string memory message) {
                emit Log(message);
                timeToMaturity64x64 = 0;
            }

            if (spot64x64 > 0 && timeToMaturity64x64 > 0) {
                _setAuctionPrices(
                    l,
                    auction,
                    epoch,
                    spot64x64,
                    timeToMaturity64x64
                );
            }
        }

        _validateAuctionPrices(auction, epoch);
    }

    /************************************************
     *  PRICING
     ***********************************************/

    /**
     * @inheritdoc IAuction
     */
    function lastPrice64x64(uint64 epoch) external view returns (int128) {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        AuctionStorage.Auction storage auction = l.auctions[epoch];
        return _lastPrice64x64(auction);
    }

    /**
     * @inheritdoc IAuction
     */
    function priceCurve64x64(uint64 epoch) external view returns (int128) {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        AuctionStorage.Auction storage auction = l.auctions[epoch];
        return _priceCurve64x64(auction);
    }

    /**
     * @inheritdoc IAuction
     */
    function clearingPrice64x64(uint64 epoch) external view returns (int128) {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        AuctionStorage.Auction storage auction = l.auctions[epoch];
        return _clearingPrice64x64(auction);
    }

    /************************************************
     *  PURCHASE
     ***********************************************/

    /**
     * @inheritdoc IAuction
     */
    function addLimitOrder(
        uint64 epoch,
        int128 price64x64,
        uint256 size
    ) external payable nonReentrant {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        AuctionStorage.Auction storage auction = l.auctions[epoch];

        _limitOrdersAllowed(auction);

        uint256 cost = _validateLimitOrder(l, price64x64, size);
        uint256 credited = _wrapNativeToken(cost);
        // an approve() by the msg.sender is required beforehand
        ERC20.safeTransferFrom(msg.sender, address(this), cost - credited);
        _addOrder(l, auction, epoch, price64x64, size, true);
    }

    /**
     * @inheritdoc IAuction
     */
    function swapAndAddLimitOrder(
        IExchangeHelper.SwapArgs calldata s,
        uint64 epoch,
        int128 price64x64,
        uint256 size
    ) external payable nonReentrant {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        AuctionStorage.Auction storage auction = l.auctions[epoch];

        _limitOrdersAllowed(auction);

        uint256 cost = _validateLimitOrder(l, price64x64, size);
        uint256 credited = _swapForPoolTokens(l.Exchange, s, address(ERC20));
        _transferAssets(credited, cost, msg.sender);
        _addOrder(l, auction, epoch, price64x64, size, true);
    }

    /**
     * @inheritdoc IAuction
     */
    function cancelLimitOrder(uint64 epoch, uint128 orderId)
        external
        nonReentrant
    {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        AuctionStorage.Auction storage auction = l.auctions[epoch];

        _limitOrdersAllowed(auction);

        require(orderId > 0, "invalid order id");

        OrderBook.Index storage orderbook = l.orderbooks[epoch];
        OrderBook.Data memory data = orderbook._getOrderById(orderId);

        require(data.buyer != address(0), "order does not exist");
        require(data.buyer == msg.sender, "buyer != msg.sender");

        orderbook._remove(orderId);
        // removes unique order id associated with epoch and id
        _removeUniqueOrderId(l, epoch, orderId);

        if (block.timestamp >= auction.startTime) {
            _finalizeAuction(l, auction, epoch);
        }

        uint256 cost = data.price64x64.mulu(data.size);
        ERC20.safeTransfer(msg.sender, cost);

        emit OrderCanceled(epoch, orderId, msg.sender);
    }

    /**
     * @inheritdoc IAuction
     */
    function addMarketOrder(
        uint64 epoch,
        uint256 size,
        uint256 maxCost
    ) external payable nonReentrant {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        AuctionStorage.Auction storage auction = l.auctions[epoch];

        _marketOrdersAllowed(auction);

        (int128 price64x64, uint256 cost) =
            _validateMarketOrder(l, auction, size, maxCost);

        uint256 credited = _wrapNativeToken(cost);
        // an approve() by the msg.sender is required beforehand
        ERC20.safeTransferFrom(msg.sender, address(this), cost - credited);
        _addOrder(l, auction, epoch, price64x64, size, false);
    }

    /**
     * @inheritdoc IAuction
     */
    function swapAndAddMarketOrder(
        IExchangeHelper.SwapArgs calldata s,
        uint64 epoch,
        uint256 size,
        uint256 maxCost
    ) external payable nonReentrant {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        AuctionStorage.Auction storage auction = l.auctions[epoch];

        _marketOrdersAllowed(auction);

        (int128 price64x64, uint256 cost) =
            _validateMarketOrder(l, auction, size, maxCost);

        uint256 credited = _swapForPoolTokens(l.Exchange, s, address(ERC20));
        _transferAssets(credited, cost, msg.sender);
        _addOrder(l, auction, epoch, price64x64, size, false);
    }

    /************************************************
     *  WITHDRAW
     ***********************************************/

    /**
     * @inheritdoc IAuction
     */
    function withdraw(uint64 epoch) external nonReentrant {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        AuctionStorage.Auction storage auction = l.auctions[epoch];

        require(
            AuctionStorage.Status.PROCESSED == auction.status ||
                AuctionStorage.Status.CANCELLED == auction.status,
            "status != processed || cancelled"
        );

        if (AuctionStorage.Status.PROCESSED == auction.status) {
            // long tokens are withheld for 24 hours after the auction has been processed, otherwise
            // if a long position is exercised within 24 hours of the position being underwritten
            // the collateral from the position will be moved to the pools "free liquidity" queue.
            require(
                block.timestamp >= auction.processedTime + 24 hours,
                "hold period has not ended"
            );
        }

        _withdraw(l, epoch);
    }

    /**
     * @inheritdoc IAuction
     */
    function previewWithdraw(uint64 epoch) external returns (uint256, uint256) {
        return _previewWithdraw(epoch, msg.sender);
    }

    /**
     * @inheritdoc IAuction
     */
    function previewWithdraw(uint64 epoch, address buyer)
        external
        returns (uint256, uint256)
    {
        return _previewWithdraw(epoch, buyer);
    }

    /************************************************
     *  FINALIZE AUCTION
     ***********************************************/

    /**
     * @inheritdoc IAuction
     */
    function finalizeAuction(uint64 epoch) external {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        AuctionStorage.Auction storage auction = l.auctions[epoch];

        if (
            block.timestamp > auction.endTime + 24 hours &&
            (auction.status == AuctionStorage.Status.INITIALIZED ||
                auction.status == AuctionStorage.Status.FINALIZED)
        ) {
            // cancel the auction if it has not been processed within 24 hours of the
            // auction end time so that buyers may withdraw their refunded amount
            _cancel(auction, epoch);
        } else if (
            block.timestamp >= auction.startTime &&
            auction.status == AuctionStorage.Status.INITIALIZED
        ) {
            // finalize the auction only if the auction has started
            _finalizeAuction(l, auction, epoch);
        }
    }

    /**
     * @inheritdoc IAuction
     */
    function processAuction(uint64 epoch)
        external
        onlyVault
        returns (uint256, uint256)
    {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        AuctionStorage.Auction storage auction = l.auctions[epoch];

        require(
            AuctionStorage.Status.FINALIZED == auction.status,
            "status != finalized"
        );

        auction.totalPremiums = _lastPrice64x64(auction).mulu(
            auction.totalContractsSold
        );

        ERC20.safeTransfer(address(Vault), auction.totalPremiums);

        auction.processedTime = block.timestamp;

        _updateStatus(auction, AuctionStorage.Status.PROCESSED, epoch);
        return (auction.totalPremiums, auction.totalContractsSold);
    }

    /************************************************
     *  VIEW
     ***********************************************/

    /**
     * @inheritdoc IAuction
     */
    function getAuction(uint64 epoch)
        external
        view
        returns (AuctionStorage.Auction memory)
    {
        return AuctionStorage._getAuction(epoch);
    }

    /**
     * @inheritdoc IAuction
     */
    function getDeltaOffset64x64() external view returns (int128) {
        return AuctionStorage._getDeltaOffset64x64();
    }

    /**
     * @inheritdoc IAuction
     */
    function getMinSize() external view returns (uint256) {
        return AuctionStorage._getMinSize();
    }

    /**
     * @inheritdoc IAuction
     */
    function getOrderById(uint64 epoch, uint128 orderId)
        external
        view
        returns (OrderBook.Data memory)
    {
        return AuctionStorage._getOrderById(epoch, orderId);
    }

    /**
     * @inheritdoc IAuction
     */
    function getStatus(uint64 epoch)
        external
        view
        returns (AuctionStorage.Status)
    {
        return AuctionStorage._getStatus(epoch);
    }

    /**
     * @inheritdoc IAuction
     */
    function getTotalContracts(uint64 epoch) external view returns (uint256) {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        AuctionStorage.Auction storage auction = l.auctions[epoch];

        // returns the stored total contracts if the auction has started
        if (auction.startTime > 0 && block.timestamp >= auction.startTime) {
            return AuctionStorage._getTotalContracts(epoch);
        }

        return 0;
    }

    /**
     * @inheritdoc IAuction
     */
    function getTotalContractsSold(uint64 epoch)
        external
        view
        returns (uint256)
    {
        return AuctionStorage._getTotalContractsSold(epoch);
    }

    /**
     * @inheritdoc IAuction
     */
    function getUniqueOrderIds(address buyer)
        external
        view
        returns (uint256[] memory)
    {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        EnumerableSet.UintSet storage uoids = l.uoids[buyer];

        uint256[] memory _uoids = new uint256[](uoids.length());

        unchecked {
            for (uint256 i; i < uoids.length(); ++i) {
                uint256 uoid = uoids.at(i);
                _uoids[i] = uoid;
            }
        }

        return _uoids;
    }

    /************************************************
     *  ERC165 SUPPORT
     ***********************************************/

    /**
     * @inheritdoc IERC165
     */
    function supportsInterface(bytes4 interfaceId)
        external
        view
        returns (bool)
    {
        return ERC165Storage.layout().isSupportedInterface(interfaceId);
    }

    /************************************************
     *  ERC1155 SUPPORT
     ***********************************************/

    /**
     * @inheritdoc IERC1155Receiver
     */
    function onERC1155Received(
        address,
        address,
        uint256,
        uint256,
        bytes memory
    ) external pure returns (bytes4) {
        return this.onERC1155Received.selector;
    }

    /**
     * @inheritdoc IERC1155Receiver
     */
    function onERC1155BatchReceived(
        address,
        address,
        uint256[] memory,
        uint256[] memory,
        bytes memory
    ) external pure returns (bytes4) {
        return this.onERC1155BatchReceived.selector;
    }
}

File 2 of 46 : ERC165Storage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

library ERC165Storage {
    struct Layout {
        mapping(bytes4 => bool) supportedInterfaces;
    }

    bytes32 internal constant STORAGE_SLOT =
        keccak256('solidstate.contracts.storage.ERC165');

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }

    function isSupportedInterface(Layout storage l, bytes4 interfaceId)
        internal
        view
        returns (bool)
    {
        return l.supportedInterfaces[interfaceId];
    }

    function setSupportedInterface(
        Layout storage l,
        bytes4 interfaceId,
        bool status
    ) internal {
        require(interfaceId != 0xffffffff, 'ERC165: invalid interface id');
        l.supportedInterfaces[interfaceId] = status;
    }
}

File 3 of 46 : Multicall.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IMulticall } from './IMulticall.sol';

/**
 * @title Utility contract for supporting processing of multiple function calls in a single transaction
 */
abstract contract Multicall is IMulticall {
    /**
     * @inheritdoc IMulticall
     */
    function multicall(bytes[] calldata data)
        external
        returns (bytes[] memory results)
    {
        results = new bytes[](data.length);

        unchecked {
            for (uint256 i; i < data.length; i++) {
                (bool success, bytes memory returndata) = address(this)
                    .delegatecall(data[i]);

                if (success) {
                    results[i] = returndata;
                } else {
                    assembly {
                        returndatacopy(0, 0, returndatasize())
                        revert(0, returndatasize())
                    }
                }
            }
        }

        return results;
    }
}

File 4 of 46 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { ReentrancyGuardStorage } from './ReentrancyGuardStorage.sol';

/**
 * @title Utility contract for preventing reentrancy attacks
 */
abstract contract ReentrancyGuard {
    modifier nonReentrant() {
        ReentrancyGuardStorage.Layout storage l = ReentrancyGuardStorage
            .layout();
        require(l.status != 2, 'ReentrancyGuard: reentrant call');
        l.status = 2;
        _;
        l.status = 1;
    }
}

File 5 of 46 : AuctionInternal.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@solidstate/contracts/access/ownable/OwnableInternal.sol";
import "@solidstate/contracts/token/ERC1155/IERC1155.sol";
import "@solidstate/contracts/token/ERC20/IERC20.sol";
import "@solidstate/contracts/token/ERC20/metadata/IERC20Metadata.sol";
import "@solidstate/contracts/utils/IWETH.sol";
import "@solidstate/contracts/utils/SafeCast.sol";
import "@solidstate/contracts/utils/SafeERC20.sol";

import "../libraries/OptionMath.sol";

import "../vendor/IPremiaPool.sol";

import "../vault/IVault.sol";

import "./AuctionStorage.sol";
import "./IAuctionEvents.sol";

/**
 * @title Knox Dutch Auction Internal Contract
 */

contract AuctionInternal is IAuctionEvents, OwnableInternal {
    using ABDKMath64x64 for int128;
    using ABDKMath64x64 for uint256;
    using ABDKMath64x64Token for int128;
    using ABDKMath64x64Token for uint256;
    using AuctionStorage for AuctionStorage.Layout;
    using EnumerableSet for EnumerableSet.UintSet;
    using OptionMath for uint256;
    using OrderBook for OrderBook.Index;
    using SafeCast for uint256;
    using SafeERC20 for IERC20;
    using SafeERC20 for IWETH;

    bool internal immutable isCall;
    uint8 internal immutable baseDecimals;
    uint8 internal immutable underlyingDecimals;

    IERC20 public immutable ERC20;
    IPremiaPool public immutable Pool;
    IVault public immutable Vault;
    IWETH public immutable WETH;

    constructor(
        bool _isCall,
        address pool,
        address vault,
        address weth
    ) {
        isCall = _isCall;

        Pool = IPremiaPool(pool);
        IPremiaPool.PoolSettings memory settings = Pool.getPoolSettings();
        address asset = isCall ? settings.underlying : settings.base;

        baseDecimals = IERC20Metadata(settings.base).decimals();
        underlyingDecimals = IERC20Metadata(settings.underlying).decimals();

        ERC20 = IERC20(asset);
        Vault = IVault(vault);
        WETH = IWETH(weth);
    }

    /************************************************
     *  ACCESS CONTROL
     ***********************************************/

    /**
     * @dev Throws if called by any account other than the vault
     */
    modifier onlyVault() {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        require(msg.sender == address(Vault), "!vault");
        _;
    }

    /**
     * @dev Throws if limit orders are not allowed
     * @param auction storage params
     */
    function _limitOrdersAllowed(AuctionStorage.Auction storage auction)
        internal
        view
    {
        require(
            AuctionStorage.Status.INITIALIZED == auction.status,
            "status != initialized"
        );
        _auctionHasNotEnded(auction);
    }

    /**
     * @dev Throws if market orders are not allowed
     * @param auction storage params
     */
    function _marketOrdersAllowed(AuctionStorage.Auction storage auction)
        internal
        view
    {
        require(
            AuctionStorage.Status.INITIALIZED == auction.status,
            "status != initialized"
        );
        _auctionHasStarted(auction);
        _auctionHasNotEnded(auction);
    }

    /**
     * @dev Throws if auction has not started.
     * @param auction storage params
     */
    function _auctionHasStarted(AuctionStorage.Auction storage auction)
        private
        view
    {
        require(auction.startTime > 0, "start time is not set");
        require(block.timestamp >= auction.startTime, "auction not started");
    }

    /**
     * @dev Throws if auction has ended.
     * @param auction storage params
     */
    function _auctionHasNotEnded(AuctionStorage.Auction storage auction)
        private
        view
    {
        require(auction.endTime > 0, "end time is not set");
        require(block.timestamp <= auction.endTime, "auction has ended");
    }

    /************************************************
     *  PRICING
     ***********************************************/

    /**
     * @notice returns the last price paid during the auction
     * @param auction storage params
     * @return price as 64x64 fixed point number
     */
    function _lastPrice64x64(AuctionStorage.Auction storage auction)
        internal
        view
        returns (int128)
    {
        return auction.lastPrice64x64;
    }

    /**
     * @notice calculates the current price using the price curve function
     * @param auction storage params
     * @return price as 64x64 fixed point number
     */
    function _priceCurve64x64(AuctionStorage.Auction storage auction)
        internal
        view
        returns (int128)
    {
        uint256 startTime = auction.startTime;
        uint256 totalTime = auction.endTime - auction.startTime;

        int128 maxPrice64x64 = auction.maxPrice64x64;
        int128 minPrice64x64 = auction.minPrice64x64;

        /**
         *
         * price curve equation:
         * assumes max price is always greater than min price
         * assumes the time remaining is in the range of 0 and 1
         * ------------------------------
         * time_remaning_percent(t) = (t - time_start) / time_total
         * price(t) = max_price - time_remaning_percent(t) * (max_price - min_price)
         *
         */

        if (block.timestamp <= startTime) return maxPrice64x64;
        if (block.timestamp >= auction.endTime) return minPrice64x64;

        uint256 elapsed = block.timestamp - startTime;
        int128 timeRemaining64x64 = elapsed.divu(totalTime);

        int128 x = maxPrice64x64.sub(minPrice64x64);
        int128 y = timeRemaining64x64.mul(x);
        return maxPrice64x64.sub(y);
    }

    /**
     * @notice returns the current price established by the price curve if the auction
     * is still ongoing, otherwise the last price paid is returned
     * @param auction storage params
     * @return price as 64x64 fixed point number
     */
    function _clearingPrice64x64(AuctionStorage.Auction storage auction)
        internal
        view
        returns (int128)
    {
        if (
            auction.status == AuctionStorage.Status.FINALIZED ||
            auction.status == AuctionStorage.Status.PROCESSED ||
            auction.status == AuctionStorage.Status.CANCELLED
        ) {
            return _lastPrice64x64(auction);
        }
        return _priceCurve64x64(auction);
    }

    /**
     * @notice calculates and sets the option max and min price
     * @param l auction storage layout
     * @param auction storage params
     * @param epoch epoch id
     * @param spot64x64 spot price of the underlying as 64x64 fixed point number
     * @param timeToMaturity64x64 time remaining until maturity as a 64x64 fixed point number
     */
    function _setAuctionPrices(
        AuctionStorage.Layout storage l,
        AuctionStorage.Auction storage auction,
        uint64 epoch,
        int128 spot64x64,
        int128 timeToMaturity64x64
    ) internal {
        int128 strike64x64 = auction.strike64x64;

        // calculates the further OTM strike price
        int128 offsetAmount64x64 = strike64x64.mul(l.deltaOffset64x64);
        int128 offsetStrike64x64 =
            isCall
                ? strike64x64.add(offsetAmount64x64)
                : strike64x64.sub(offsetAmount64x64);

        /**
         * it is assumed that the rounded strike price will always be further ITM than the offset
         * strike price. the further ITM option will always be more expensive and will therefore
         * be used to determine the max price of the auction. likewise, the offset strike price
         * (further OTM) should resemble a cheaper option and it is therefore used as the min
         * option price in our auction.
         *
         *
         * Call Option
         * -----------
         * Strike    Rounded Strike             Offset Strike
         *   |  ---------> |                          |
         *   |             |                          |
         * -----------------------Price------------------------>
         *
         *
         * Put Option
         * -----------
         * Offset Strike              Rounded Strike    Strike
         *       |                           | <--------- |
         *       |                           |            |
         * -----------------------Price------------------------>
         *
         *
         */

        // calculates the auction max price using the strike price (further ITM)
        auction.maxPrice64x64 = l.Pricer.getBlackScholesPrice64x64(
            spot64x64,
            strike64x64,
            timeToMaturity64x64,
            isCall
        );

        // calculates the auction min price using the offset strike price (further OTM)
        auction.minPrice64x64 = l.Pricer.getBlackScholesPrice64x64(
            spot64x64,
            offsetStrike64x64,
            timeToMaturity64x64,
            isCall
        );

        if (isCall) {
            // denominates price in the collateral asset
            auction.maxPrice64x64 = auction.maxPrice64x64.div(spot64x64);
            auction.minPrice64x64 = auction.minPrice64x64.div(spot64x64);
        }

        emit AuctionPricesSet(
            epoch,
            strike64x64,
            offsetStrike64x64,
            spot64x64,
            auction.maxPrice64x64,
            auction.minPrice64x64
        );
    }

    /**
     * @notice validates the max and min prices
     * @param auction storage params
     * @param epoch epoch id
     */
    function _validateAuctionPrices(
        AuctionStorage.Auction storage auction,
        uint64 epoch
    ) internal {
        if (
            auction.maxPrice64x64 <= 0 ||
            auction.minPrice64x64 <= 0 ||
            auction.maxPrice64x64 <= auction.minPrice64x64
        ) {
            // if either price is 0 or the max price is less than or equal to the min price,
            // the auction should always be cancelled.
            _cancel(auction, epoch);
        }
    }

    /************************************************
     *  WITHDRAW
     ***********************************************/

    /**
     * @notice withdraws any amount(s) owed to the buyer (fill and/or refund)
     * @param l auction storage layout
     * @param epoch epoch id
     */
    function _withdraw(AuctionStorage.Layout storage l, uint64 epoch) internal {
        (uint256 refund, uint256 fill) =
            _previewWithdraw(l, false, epoch, msg.sender);

        // removes all unique order ids associated with epoch
        _removeUniqueOrderId(l, epoch, 0);

        // fetches the exercised value of the options
        (bool expired, uint256 exercisedAmount) =
            _getExerciseAmount(l, epoch, fill);

        if (expired) {
            if (exercisedAmount > 0) {
                // if expired ITM, adjust refund by the amount exercised
                refund += exercisedAmount;
            }

            // set fill to 0, buyer will not receive any long tokens
            fill = 0;
        }

        if (fill > 0) {
            // transfers long tokens to msg.sender
            Pool.safeTransferFrom(
                address(this),
                msg.sender,
                l.auctions[epoch].longTokenId,
                fill,
                ""
            );
        }

        if (refund > 0) {
            // transfers refunded premium to msg.sender
            ERC20.safeTransfer(msg.sender, refund);
        }

        emit OrderWithdrawn(epoch, msg.sender, refund, fill);
    }

    /**
     * @notice calculates amount(s) owed to the buyer
     * @param epoch epoch id
     * @param buyer address of buyer
     * @return amount refunded
     * @return amount filled
     */
    function _previewWithdraw(uint64 epoch, address buyer)
        internal
        returns (uint256, uint256)
    {
        AuctionStorage.Layout storage l = AuctionStorage.layout();
        return _previewWithdraw(l, true, epoch, buyer);
    }

    /**
     * @notice traverses the orderbook and returns the refund and fill amounts
     * @param l auction storage layout
     * @param epoch epoch id
     * @param buyer address of buyer
     * @return amount refunded
     * @return amount filled
     */
    function _previewWithdraw(
        AuctionStorage.Layout storage l,
        bool isPreview,
        uint64 epoch,
        address buyer
    ) private returns (uint256, uint256) {
        AuctionStorage.Auction storage auction = l.auctions[epoch];
        OrderBook.Index storage orderbook = l.orderbooks[epoch];

        uint256 refund;
        uint256 fill;

        int128 lastPrice64x64 = _clearingPrice64x64(auction);
        uint256 totalUnclaimedContracts = auction.totalUnclaimedContracts;

        // traverse the order book and return orders placed by the buyer until the end of the orderbook has been reached
        OrderBook.Data memory data = orderbook._getOrderById(orderbook._head());
        do {
            uint256 next = orderbook._getNextOrder(data.id);

            if (data.buyer == buyer) {
                uint256 claimed;
                uint256 paid = data.price64x64.mulu(data.size);

                if (
                    auction.status != AuctionStorage.Status.CANCELLED &&
                    totalUnclaimedContracts > 0 &&
                    data.price64x64 >= lastPrice64x64
                ) {
                    // if the auction has not been cancelled, and the order price is greater than or
                    // equal to the last price, fill the order and calculate the refund amount
                    uint256 cost = lastPrice64x64.mulu(data.size);

                    if (data.size > totalUnclaimedContracts) {
                        // if part of the current order exceeds the total contracts available, partially
                        // fill the order, and refund the remainder
                        cost = lastPrice64x64.mulu(totalUnclaimedContracts);
                        fill += totalUnclaimedContracts;
                        claimed += totalUnclaimedContracts;
                    } else {
                        // otherwise, fill the entire order
                        fill += data.size;
                        claimed += data.size;
                    }
                    // the refund takes the difference between the amount paid and the "true" cost of
                    // of the order. the "true" cost can be calculated when the clearing price has been
                    // set.
                    refund += paid - cost;
                } else {
                    // if no contracts are available, the auction has been cancelled, or the bid is too
                    // low, only send refund
                    refund += paid;
                }

                if (!isPreview) {
                    // if the buyer has a filled order, remove it from the unclaimed
                    // contract balance
                    auction.totalUnclaimedContracts -= claimed;

                    // when a withdrawal is made, remove the order from the order book
                    orderbook._remove(data.id);
                }

                // claimed amount is reset after every filled order
                claimed = 0;
            }

            if (totalUnclaimedContracts > 0) {
                if (data.size > totalUnclaimedContracts) {
                    totalUnclaimedContracts = 0;
                } else {
                    totalUnclaimedContracts -= data.size;
                }
            }

            data = orderbook._getOrderById(next);
        } while (data.id != 0);

        return (refund, fill);
    }

    /************************************************
     *  FINALIZE AUCTION
     ***********************************************/

    /**
     * @notice traverses the orderbook and checks if the auction has reached 100% utilization
     * @param l auction storage layout
     * @param epoch epoch id
     * @return true if the auction has reached 100% utilization
     */
    function _processOrders(AuctionStorage.Layout storage l, uint64 epoch)
        private
        returns (bool)
    {
        OrderBook.Index storage orderbook = l.orderbooks[epoch];
        AuctionStorage.Auction storage auction = l.auctions[epoch];

        // if the total contracts has not been set for the auction, the vault contract will be
        // queried and the amount will be determined from the collateral in the vault.
        if (auction.totalContracts <= 0) {
            uint256 totalContracts = _getTotalContracts(auction);

            // auction is cancelled if there are no contracts available
            if (totalContracts <= 0) {
                _cancel(auction, epoch);
                return false;
            }

            auction.totalContracts = totalContracts;
        }

        uint256 totalContractsSold;
        int128 lastPrice64x64;

        // traverse the order book and sum the contracts sold until the utilization == 100% or
        // the end of the orderbook has been reached
        OrderBook.Data memory data = orderbook._getOrderById(orderbook._head());
        do {
            uint256 next = orderbook._getNextOrder(data.id);

            // orders in the order book are sorted by price in a descending order. if the
            // order price < clearing price the last order which should be accepeted has
            // been reached.
            if (data.price64x64 < _clearingPrice64x64(auction)) break;

            // checks if utilization >= 100%
            if (totalContractsSold + data.size >= auction.totalContracts) {
                auction.lastPrice64x64 = data.price64x64;
                auction.totalContractsSold = auction.totalContracts;
                return true;
            }

            totalContractsSold += data.size;
            lastPrice64x64 = data.price64x64;

            data = orderbook._getOrderById(next);
        } while (data.id != 0);

        /**
         * sets the last price reached in the order book equal to the last price paid in the auction.
         *
         *
         * Orderbook | price curve == 96
         * ---------
         * id -  price
         * 0  -  100
         * 1  -  97 --- last price
         * 2  -  95
         * */

        auction.lastPrice64x64 = lastPrice64x64;
        auction.totalContractsSold = totalContractsSold;
        return false;
    }

    /**
     * @notice determines whether the auction has reached finality. the end criteria for the auction are
     * met if the auction has reached 100% utilization or the end time has been exceeded.
     * @param l auction storage layout
     * @param auction storage params
     * @param epoch epoch id
     */
    function _finalizeAuction(
        AuctionStorage.Layout storage l,
        AuctionStorage.Auction storage auction,
        uint64 epoch
    ) internal {
        _validateAuctionPrices(auction, epoch);

        if (
            auction.status != AuctionStorage.Status.CANCELLED &&
            (_processOrders(l, epoch) || block.timestamp > auction.endTime)
        ) {
            if (auction.totalContractsSold > 0) {
                auction.totalUnclaimedContracts = auction.totalContractsSold;
                _updateStatus(auction, AuctionStorage.Status.FINALIZED, epoch);
            } else {
                _cancel(auction, epoch);
            }
        }
    }

    /************************************************
     *  VIEW
     ***********************************************/

    /**
     * @notice calculates the total number of contracts that can be sold during the auction
     * @param auction storage params
     * @return total contracts available
     */
    function _getTotalContracts(AuctionStorage.Auction storage auction)
        private
        view
        returns (uint256)
    {
        uint256 collateral = Vault.totalCollateral();
        uint256 reserves = Vault.previewReserves();

        return
            collateral > reserves
                ? (collateral - reserves).fromCollateralToContracts(
                    isCall,
                    baseDecimals,
                    auction.strike64x64
                )
                : 0;
    }

    /************************************************
     *  PURCHASE HELPERS
     ***********************************************/

    /**
     * @notice checks whether the limit order parameters are valid and returns the cost
     * @param l auction storage layout
     * @param price64x64 max price as 64x64 fixed point number
     * @param size amount of contracts
     * @return cost of the order given the size and price
     */
    function _validateLimitOrder(
        AuctionStorage.Layout storage l,
        int128 price64x64,
        uint256 size
    ) internal view returns (uint256) {
        require(price64x64 > 0, "price <= 0");
        require(size >= l.minSize, "size < minimum");

        uint256 cost = price64x64.mulu(size);
        return cost;
    }

    /**
     * @notice checks whether the market order parameters are valid and returns the price and cost
     * @param l auction storage layout
     * @param auction storage params
     * @param size amount of contracts
     * @param maxCost max cost of buyer is willing to pay
     * @return price established by the price curve
     * @return cost of the order given the size and price
     */
    function _validateMarketOrder(
        AuctionStorage.Layout storage l,
        AuctionStorage.Auction storage auction,
        uint256 size,
        uint256 maxCost
    ) internal view returns (int128, uint256) {
        require(size >= l.minSize, "size < minimum");

        int128 price64x64 = _priceCurve64x64(auction);
        uint256 cost = price64x64.mulu(size);

        require(maxCost >= cost, "cost > maxCost");
        return (price64x64, cost);
    }

    /**
     * @notice transfers the premium to the buyer if a refund is due, ortherwise, pull funds
     * from buyer if funds are owed to the auction contract.
     * @param credited amount already paid by the buyer
     * @param cost total amount which must be paid by the buyer
     * @param buyer account being debited or credited
     */
    function _transferAssets(
        uint256 credited,
        uint256 cost,
        address buyer
    ) internal {
        if (credited > cost) {
            // refund buyer the amount overpaid
            ERC20.safeTransfer(buyer, credited - cost);
        } else if (cost > credited) {
            // an approve() by the msg.sender is required beforehand
            ERC20.safeTransferFrom(buyer, address(this), cost - credited);
        }
    }

    /**
     * @notice checks whether the market order parameters are valid and returns the price and cost
     * @param l auction storage layout
     * @param auction storage params
     * @param epoch epoch id
     * @param price64x64 max price as 64x64 fixed point number
     * @param size amount of contracts
     * @param isLimitOrder true, if the order is a limit order
     */
    function _addOrder(
        AuctionStorage.Layout storage l,
        AuctionStorage.Auction storage auction,
        uint64 epoch,
        int128 price64x64,
        uint256 size,
        bool isLimitOrder
    ) internal {
        uint128 orderId =
            l.orderbooks[epoch]
                ._insert(price64x64, size, msg.sender)
                .toUint128();

        // format the unique order id and add it to storage
        uint256 uoid = AuctionStorage._formatUniqueOrderId(epoch, orderId);
        l.uoids[msg.sender].add(uoid);

        if (block.timestamp >= auction.startTime) {
            _finalizeAuction(l, auction, epoch);
        }

        emit OrderAdded(
            epoch,
            orderId,
            msg.sender,
            price64x64,
            size,
            isLimitOrder
        );
    }

    /**
     * @notice wraps ETH sent to the contract and credits the amount, if the collateral asset
     * is not WETH, the transaction will revert
     * @param amount total collateral deposited
     * @return credited amount
     */
    function _wrapNativeToken(uint256 amount) internal returns (uint256) {
        uint256 credit;

        if (msg.value > 0) {
            require(address(ERC20) == address(WETH), "collateral != wETH");

            if (msg.value > amount) {
                // if the ETH amount is greater than the amount needed, it will be sent
                // back to the msg.sender
                unchecked {
                    (bool success, ) =
                        payable(msg.sender).call{value: msg.value - amount}("");

                    require(success, "ETH refund failed");

                    credit = amount;
                }
            } else {
                credit = msg.value;
            }

            WETH.deposit{value: credit}();
        }

        return credit;
    }

    /**
     * @notice pull token from user, send to exchangeHelper trigger a trade from
     * ExchangeHelper, and credits the amount
     * @param Exchange ExchangeHelper contract interface
     * @param s swap arguments
     * @param tokenOut token to swap for. should always equal to the collateral asset
     * @return credited amount
     */
    function _swapForPoolTokens(
        IExchangeHelper Exchange,
        IExchangeHelper.SwapArgs calldata s,
        address tokenOut
    ) internal returns (uint256) {
        if (msg.value > 0) {
            require(s.tokenIn == address(WETH), "tokenIn != wETH");
            WETH.deposit{value: msg.value}();
            WETH.safeTransfer(address(Exchange), msg.value);
        }

        if (s.amountInMax > 0) {
            IERC20(s.tokenIn).safeTransferFrom(
                msg.sender,
                address(Exchange),
                s.amountInMax
            );
        }

        uint256 amountCredited =
            Exchange.swapWithToken(
                s.tokenIn,
                tokenOut,
                s.amountInMax + msg.value,
                s.callee,
                s.allowanceTarget,
                s.data,
                s.refundAddress
            );

        require(
            amountCredited >= s.amountOutMin,
            "not enough output from trade"
        );

        return amountCredited;
    }

    /************************************************
     * HELPERS
     ***********************************************/

    /**
     * @notice cancels all orders and finalizes the auction
     * @param auction the auction to cancel
     * @param epoch epoch id
     */
    function _cancel(AuctionStorage.Auction storage auction, uint64 epoch)
        internal
    {
        auction.totalPremiums = 0;
        _updateStatus(auction, AuctionStorage.Status.CANCELLED, epoch);
    }

    /**
     * @notice calculates the expected proceeds of the option if it has expired
     * @param epoch epoch id
     * @param size amount of contracts
     * @return true if the option has expired
     * @return the exercised amount
     */
    function _getExerciseAmount(
        AuctionStorage.Layout storage l,
        uint64 epoch,
        uint256 size
    ) private view returns (bool, uint256) {
        AuctionStorage.Auction storage auction = l.auctions[epoch];

        uint64 expiry = auction.expiry;
        int128 strike64x64 = auction.strike64x64;

        if (block.timestamp < expiry) return (false, 0);

        int128 spot64x64 = Pool.getPriceAfter64x64(expiry);
        uint256 amount;

        if (isCall && spot64x64 > strike64x64) {
            amount = spot64x64.sub(strike64x64).div(spot64x64).mulu(size);
        } else if (!isCall && strike64x64 > spot64x64) {
            uint256 value = strike64x64.sub(spot64x64).mulu(size);

            // converts the value to the base asset amount, this is particularly important where the
            // the decimals of the underlying are different from the base (e.g. wBTC/DAI)
            amount = OptionMath.toBaseTokenAmount(
                underlyingDecimals,
                baseDecimals,
                value
            );
        }

        return (true, amount);
    }

    /**
     * @notice removes the active unique order id from uoids mapping
     * @param l auction storage layout
     * @param epoch epoch id
     * @param orderId order id
     */
    function _removeUniqueOrderId(
        AuctionStorage.Layout storage l,
        uint64 epoch,
        uint128 orderId
    ) internal {
        EnumerableSet.UintSet storage uoids = l.uoids[msg.sender];

        unchecked {
            for (uint256 i; i < uoids.length(); ++i) {
                uint256 uoid = uoids.at(i);
                (, uint64 _epoch, uint128 _orderId) =
                    AuctionStorage._parseUniqueOrderId(uoid);

                if (
                    (orderId == 0 && _epoch == epoch) ||
                    (_orderId == orderId && _epoch == epoch)
                ) {
                    uoids.remove(uoid);
                }
            }
        }
    }

    function _updateStatus(
        AuctionStorage.Auction storage auction,
        AuctionStorage.Status status,
        uint64 epoch
    ) internal {
        auction.status = status;
        emit AuctionStatusSet(epoch, auction.status);
    }
}

File 6 of 46 : IAuction.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@solidstate/contracts/introspection/IERC165.sol";
import "@solidstate/contracts/token/ERC1155/IERC1155Receiver.sol";
import "@solidstate/contracts/utils/IMulticall.sol";

import "../vendor/IExchangeHelper.sol";

import "./AuctionStorage.sol";
import "./IAuctionEvents.sol";

/**
 * @title Knox Auction Interface
 */

interface IAuction is IAuctionEvents, IERC165, IERC1155Receiver, IMulticall {
    /************************************************
     *  ADMIN
     ***********************************************/

    /**
     * @notice sets the percent offset from delta strike
     * @param newDeltaOffset64x64 new percent offset value as a 64x64 fixed point number
     */
    function setDeltaOffset64x64(int128 newDeltaOffset64x64) external;

    /**
     * @notice sets a new Exchange Helper contract
     * @param newExchangeHelper new Exchange Helper contract address
     */
    function setExchangeHelper(address newExchangeHelper) external;

    /**
     * @notice sets a new minimum order size
     * @param newMinSize new minimum order size
     */
    function setMinSize(uint256 newMinSize) external;

    /**
     * @notice sets the new pricer
     * @dev the pricer contract address must be set during the vault initialization
     * @param newPricer address of the new pricer
     */
    function setPricer(address newPricer) external;

    /************************************************
     *  INITIALIZE AUCTION
     ***********************************************/

    /**
     * @notice initializes a new auction
     * @param initAuction auction parameters
     */
    function initialize(AuctionStorage.InitAuction memory initAuction) external;

    /**
     * @notice sets the auction max/min prices
     * @param epoch epoch id
     */
    function setAuctionPrices(uint64 epoch) external;

    /************************************************
     *  PRICING
     ***********************************************/

    /**
     * @notice returns the last price paid during the auction
     * @param epoch epoch id
     * @return price as 64x64 fixed point number
     */
    function lastPrice64x64(uint64 epoch) external view returns (int128);

    /**
     * @notice calculates the current price using the price curve function
     * @param epoch epoch id
     * @return price as 64x64 fixed point number
     */
    function priceCurve64x64(uint64 epoch) external view returns (int128);

    /**
     * @notice returns the current price established by the price curve if the auction
     * is still ongoing, otherwise the last price paid is returned
     * @param epoch epoch id
     * @return price as 64x64 fixed point number
     */
    function clearingPrice64x64(uint64 epoch) external view returns (int128);

    /************************************************
     *  PURCHASE
     ***********************************************/

    /**
     * @notice adds an order specified by the price and size
     * @dev sent ETH will be wrapped as wETH, sender must approve contract
     * @param epoch epoch id
     * @param price64x64 max price as 64x64 fixed point number
     * @param size amount of contracts
     */
    function addLimitOrder(
        uint64 epoch,
        int128 price64x64,
        uint256 size
    ) external payable;

    /**
     * @notice swaps into the collateral asset and adds an order specified by the price and size
     * @dev sent ETH will be wrapped as wETH, sender must approve contract
     * @param s swap arguments
     * @param epoch epoch id
     * @param price64x64 max price as 64x64 fixed point number
     * @param size amount of contracts
     */
    function swapAndAddLimitOrder(
        IExchangeHelper.SwapArgs calldata s,
        uint64 epoch,
        int128 price64x64,
        uint256 size
    ) external payable;

    /**
     * @notice cancels an order
     * @dev sender must approve contract
     * @param epoch epoch id
     * @param orderId order id
     */
    function cancelLimitOrder(uint64 epoch, uint128 orderId) external;

    /**
     * @notice adds an order specified by size only
     * @dev sent ETH will be wrapped as wETH, sender must approve contract
     * @param epoch epoch id
     * @param size amount of contracts
     * @param maxCost max cost of buyer is willing to pay
     */
    function addMarketOrder(
        uint64 epoch,
        uint256 size,
        uint256 maxCost
    ) external payable;

    /**
     * @notice swaps into the collateral asset and adds an order specified by size only
     * @dev sent ETH will be wrapped as wETH, sender must approve contract
     * @param s swap arguments
     * @param epoch epoch id
     * @param size amount of contracts
     * @param maxCost max cost of buyer is willing to pay
     */
    function swapAndAddMarketOrder(
        IExchangeHelper.SwapArgs calldata s,
        uint64 epoch,
        uint256 size,
        uint256 maxCost
    ) external payable;

    /************************************************
     *  WITHDRAW
     ***********************************************/

    /**
     * @notice withdraws any amount(s) owed to the buyer (fill and/or refund)
     * @param epoch epoch id
     */
    function withdraw(uint64 epoch) external;

    /**
     * @notice calculates amount(s) owed to the buyer
     * @param epoch epoch id
     * @return amount refunded
     * @return amount filled
     */
    function previewWithdraw(uint64 epoch) external returns (uint256, uint256);

    /**
     * @notice calculates amount(s) owed to the buyer
     * @param epoch epoch id
     * @param buyer address of buyer
     * @return amount refunded
     * @return amount filled
     */
    function previewWithdraw(uint64 epoch, address buyer)
        external
        returns (uint256, uint256);

    /************************************************
     *  FINALIZE AUCTION
     ***********************************************/

    /**
     * @notice determines whether the auction has reached finality. the end criteria for the auction are
     * met if the auction has reached 100% utilization or the end time has been exceeded.
     * @param epoch epoch id
     */
    function finalizeAuction(uint64 epoch) external;

    /**
     * @notice transfers premiums and updates auction state
     * @param epoch epoch id
     * @return amount in premiums paid during auction
     * @return total number of contracts sold
     */
    function processAuction(uint64 epoch) external returns (uint256, uint256);

    /************************************************
     *  VIEW
     ***********************************************/

    /**
     * @notice returns the auction parameters
     * @param epoch epoch id
     * @return auction parameters
     */
    function getAuction(uint64 epoch)
        external
        view
        returns (AuctionStorage.Auction memory);

    /**
     * @notice returns percent delta offset
     * @return percent delta offset as a 64x64 fixed point number
     */
    function getDeltaOffset64x64() external view returns (int128);

    /**
     * @notice returns the minimum order size
     * @return minimum order size
     */
    function getMinSize() external view returns (uint256);

    /**
     * @notice returns the order from the auction orderbook
     * @param epoch epoch id
     * @param orderId order id
     * @return order from auction orderbook
     */
    function getOrderById(uint64 epoch, uint128 orderId)
        external
        view
        returns (OrderBook.Data memory);

    /**
     * @notice returns the status of the auction
     * @param epoch epoch id
     * @return auction status
     */
    function getStatus(uint64 epoch)
        external
        view
        returns (AuctionStorage.Status);

    /**
     * @notice returns the stored total number of contracts that can be sold during the auction
     * returns 0 if the auction has not started
     * @param epoch epoch id
     * @return total number of contracts which may be sold
     */
    function getTotalContracts(uint64 epoch) external view returns (uint256);

    /**
     * @notice returns the total number of contracts sold
     * @param epoch epoch id
     * @return total number of contracts sold
     */
    function getTotalContractsSold(uint64 epoch)
        external
        view
        returns (uint256);

    /**
     * @notice returns the active unique order ids
     * @param buyer address of buyer
     * @return array of unique order ids
     */
    function getUniqueOrderIds(address buyer)
        external
        view
        returns (uint256[] memory);
}

File 7 of 46 : IMulticall.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title Interface for the Multicall utility contract
 */
interface IMulticall {
    /**
     * @notice batch function calls to the contract and return the results of each
     * @param data array of function call data payloads
     * @return results array of function call results
     */
    function multicall(bytes[] calldata data)
        external
        returns (bytes[] memory results);
}

File 8 of 46 : ReentrancyGuardStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

library ReentrancyGuardStorage {
    struct Layout {
        uint256 status;
    }

    bytes32 internal constant STORAGE_SLOT =
        keccak256('solidstate.contracts.storage.ReentrancyGuard');

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }
}

File 9 of 46 : OwnableInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IOwnableInternal } from './IOwnableInternal.sol';
import { OwnableStorage } from './OwnableStorage.sol';

abstract contract OwnableInternal is IOwnableInternal {
    using OwnableStorage for OwnableStorage.Layout;

    modifier onlyOwner() {
        require(
            msg.sender == OwnableStorage.layout().owner,
            'Ownable: sender must be owner'
        );
        _;
    }

    function _owner() internal view virtual returns (address) {
        return OwnableStorage.layout().owner;
    }

    function _transferOwnership(address account) internal virtual {
        OwnableStorage.layout().setOwner(account);
        emit OwnershipTransferred(msg.sender, account);
    }
}

File 10 of 46 : IERC1155.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IERC1155Internal } from './IERC1155Internal.sol';
import { IERC165 } from '../../introspection/IERC165.sol';

/**
 * @title ERC1155 interface
 * @dev see https://github.com/ethereum/EIPs/issues/1155
 */
interface IERC1155 is IERC1155Internal, IERC165 {
    /**
     * @notice query the balance of given token held by given address
     * @param account address to query
     * @param id token to query
     * @return token balance
     */
    function balanceOf(address account, uint256 id)
        external
        view
        returns (uint256);

    /**
     * @notice query the balances of given tokens held by given addresses
     * @param accounts addresss to query
     * @param ids tokens to query
     * @return token balances
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    /**
     * @notice query approval status of given operator with respect to given address
     * @param account address to query for approval granted
     * @param operator address to query for approval received
     * @return whether operator is approved to spend tokens held by account
     */
    function isApprovedForAll(address account, address operator)
        external
        view
        returns (bool);

    /**
     * @notice grant approval to or revoke approval from given operator to spend held tokens
     * @param operator address whose approval status to update
     * @param status whether operator should be considered approved
     */
    function setApprovalForAll(address operator, bool status) external;

    /**
     * @notice transfer tokens between given addresses, checking for ERC1155Receiver implementation if applicable
     * @param from sender of tokens
     * @param to receiver of tokens
     * @param id token ID
     * @param amount quantity of tokens to transfer
     * @param data data payload
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @notice transfer batch of tokens between given addresses, checking for ERC1155Receiver implementation if applicable
     * @param from sender of tokens
     * @param to receiver of tokens
     * @param ids list of token IDs
     * @param amounts list of quantities of tokens to transfer
     * @param data data payload
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

File 11 of 46 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IERC20Internal } from './IERC20Internal.sol';

/**
 * @title ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
interface IERC20 is IERC20Internal {
    /**
     * @notice query the total minted token supply
     * @return token supply
     */
    function totalSupply() external view returns (uint256);

    /**
     * @notice query the token balance of given account
     * @param account address to query
     * @return token balance
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @notice query the allowance granted from given holder to given spender
     * @param holder approver of allowance
     * @param spender recipient of allowance
     * @return token allowance
     */
    function allowance(address holder, address spender)
        external
        view
        returns (uint256);

    /**
     * @notice grant approval to spender to spend tokens
     * @dev prefer ERC20Extended functions to avoid transaction-ordering vulnerability (see https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729)
     * @param spender recipient of allowance
     * @param amount quantity of tokens approved for spending
     * @return success status (always true; otherwise function should revert)
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @notice transfer tokens to given recipient
     * @param recipient beneficiary of token transfer
     * @param amount quantity of tokens to transfer
     * @return success status (always true; otherwise function should revert)
     */
    function transfer(address recipient, uint256 amount)
        external
        returns (bool);

    /**
     * @notice transfer tokens to given recipient on behalf of given holder
     * @param holder holder of tokens prior to transfer
     * @param recipient beneficiary of token transfer
     * @param amount quantity of tokens to transfer
     * @return success status (always true; otherwise function should revert)
     */
    function transferFrom(
        address holder,
        address recipient,
        uint256 amount
    ) external returns (bool);
}

File 12 of 46 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title ERC20 metadata interface
 */
interface IERC20Metadata {
    /**
     * @notice return token name
     * @return token name
     */
    function name() external view returns (string memory);

    /**
     * @notice return token symbol
     * @return token symbol
     */
    function symbol() external view returns (string memory);

    /**
     * @notice return token decimals, generally used only for display purposes
     * @return token decimals
     */
    function decimals() external view returns (uint8);
}

File 13 of 46 : IWETH.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IERC20 } from '../token/ERC20/IERC20.sol';
import { IERC20Metadata } from '../token/ERC20/metadata/IERC20Metadata.sol';

/**
 * @title WETH (Wrapped ETH) interface
 */
interface IWETH is IERC20, IERC20Metadata {
    /**
     * @notice convert ETH to WETH
     */
    function deposit() external payable;

    /**
     * @notice convert WETH to ETH
     * @dev if caller is a contract, it should have a fallback or receive function
     * @param amount quantity of WETH to convert, denominated in wei
     */
    function withdraw(uint256 amount) external;
}

File 14 of 46 : SafeCast.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title Helper library for safe casting of uint and int values
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
 */
library SafeCast {
    function toUint224(uint256 value) internal pure returns (uint224) {
        require(value <= type(uint224).max, 'SafeCast: value does not fit');
        return uint224(value);
    }

    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value <= type(uint128).max, 'SafeCast: value does not fit');
        return uint128(value);
    }

    function toUint96(uint256 value) internal pure returns (uint96) {
        require(value <= type(uint96).max, 'SafeCast: value does not fit');
        return uint96(value);
    }

    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value <= type(uint64).max, 'SafeCast: value does not fit');
        return uint64(value);
    }

    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value <= type(uint32).max, 'SafeCast: value does not fit');
        return uint32(value);
    }

    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value <= type(uint16).max, 'SafeCast: value does not fit');
        return uint16(value);
    }

    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value <= type(uint8).max, 'SafeCast: value does not fit');
        return uint8(value);
    }

    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, 'SafeCast: value must be positive');
        return uint256(value);
    }

    function toInt128(int256 value) internal pure returns (int128) {
        require(
            value >= type(int128).min && value <= type(int128).max,
            'SafeCast: value does not fit'
        );
        return int128(value);
    }

    function toInt64(int256 value) internal pure returns (int64) {
        require(
            value >= type(int64).min && value <= type(int64).max,
            'SafeCast: value does not fit'
        );
        return int64(value);
    }

    function toInt32(int256 value) internal pure returns (int32) {
        require(
            value >= type(int32).min && value <= type(int32).max,
            'SafeCast: value does not fit'
        );
        return int32(value);
    }

    function toInt16(int256 value) internal pure returns (int16) {
        require(
            value >= type(int16).min && value <= type(int16).max,
            'SafeCast: value does not fit'
        );
        return int16(value);
    }

    function toInt8(int256 value) internal pure returns (int8) {
        require(
            value >= type(int8).min && value <= type(int8).max,
            'SafeCast: value does not fit'
        );
        return int8(value);
    }

    function toInt256(uint256 value) internal pure returns (int256) {
        require(
            value <= uint256(type(int256).max),
            'SafeCast: value does not fit'
        );
        return int256(value);
    }
}

File 15 of 46 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IERC20 } from '../token/ERC20/IERC20.sol';
import { AddressUtils } from './AddressUtils.sol';

/**
 * @title Safe ERC20 interaction library
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license)
 */
library SafeERC20 {
    using AddressUtils for address;

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

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

    /**
     * @dev safeApprove (like approve) should only be called when setting an initial allowance or when resetting it to zero; otherwise prefer safeIncreaseAllowance and safeDecreaseAllowance
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            'SafeERC20: approve from non-zero to non-zero allowance'
        );

        _callOptionalReturn(
            token,
            abi.encodeWithSelector(token.approve.selector, spender, value)
        );
    }

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

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

    /**
     * @notice send transaction data and check validity of return value, if present
     * @param token ERC20 token interface
     * @param data transaction data
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        bytes memory returndata = address(token).functionCall(
            data,
            'SafeERC20: low-level call failed'
        );

        if (returndata.length > 0) {
            require(
                abi.decode(returndata, (bool)),
                'SafeERC20: ERC20 operation did not succeed'
            );
        }
    }
}

File 16 of 46 : OptionMath.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "abdk-libraries-solidity/ABDKMath64x64.sol";
import "@solidstate/abdk-math-extensions/contracts/ABDKMath64x64Token.sol";

/**
 * @title Option Math Helper Library
 */

library OptionMath {
    using ABDKMath64x64 for int128;
    using ABDKMath64x64 for uint256;
    using ABDKMath64x64Token for int128;
    using ABDKMath64x64Token for uint256;

    int256 private constant ONE = 10000000000000000000;

    struct Value {
        int256 value;
        int256 ruler;
    }

    /**
     * @custom:author Yaojin Sun
     * @notice applies ceiling to the second highest place value of a positive 64x64 fixed point number
     * @param x 64x64 fixed point number
     * @return rounded 64x64 fixed point number
     */
    function ceil64x64(int128 x) internal pure returns (int128) {
        require(x > 0);

        (int256 integer, Value[3] memory values) = _getPositivePlaceValues(x);

        // if the summation of first and second values is equal to integer, the integer has already been rounded
        if (
            values[0].ruler *
                values[0].value +
                values[1].ruler *
                values[1].value ==
            integer
        ) {
            return int128((integer << 64) / ONE);
        }

        return
            int128(
                (((values[0].ruler * values[0].value) +
                    (values[1].ruler * (values[1].value + 1))) << 64) / ONE
            );
    }

    /**
     * @custom:author Yaojin Sun
     * @notice applies floor to the second highest place value of a positive 64x64 fixed point number
     * @param x 64x64 fixed point number
     * @return rounded 64x64 fixed point number
     */
    function floor64x64(int128 x) internal pure returns (int128) {
        require(x > 0);

        (, Value[3] memory values) = _getPositivePlaceValues(x);

        // No matter whether third value is non-zero or not, we ONLY need to keep the first and second places.
        int256 res =
            (values[0].ruler * values[0].value) +
                (values[1].ruler * values[1].value);
        return int128((res << 64) / ONE);
    }

    function _getPositivePlaceValues(int128 x)
        private
        pure
        returns (int256, Value[3] memory)
    {
        // move the decimal part to integer by multiplying 10...0
        int256 integer = (int256(x) * ONE) >> 64;

        // scan and identify the highest position
        int256 ruler = 100000000000000000000000000000000000000; // 10^38
        while (integer < ruler) {
            ruler = ruler / 10;
        }

        Value[3] memory values;

        // find the first/second/third largest places and there value
        values[0] = Value(0, 0);
        values[1] = Value(0, 0);
        values[2] = Value(0, 0);

        // setup the first place value
        values[0].ruler = ruler;
        if (values[0].ruler != 0) {
            values[0].value = (integer / values[0].ruler) % 10;

            // setup the second place value
            values[1].ruler = ruler / 10;
            if (values[1].ruler != 0) {
                values[1].value = (integer / values[1].ruler) % 10;

                // setup the third place value
                values[2].ruler = ruler / 100;
                if (values[2].ruler != 0) {
                    values[2].value = (integer / values[2].ruler) % 10;
                }
            }
        }

        return (integer, values);
    }

    /**
     * @notice converts the value to the base token amount
     * @param underlyingDecimals decimal precision of the underlying asset
     * @param baseDecimals decimal precision of the base asset
     * @param value amount to convert
     * @return decimal representation of base token amount
     */
    function toBaseTokenAmount(
        uint8 underlyingDecimals,
        uint8 baseDecimals,
        uint256 value
    ) internal pure returns (uint256) {
        int128 value64x64 = value.fromDecimals(underlyingDecimals);
        return value64x64.toDecimals(baseDecimals);
    }

    /**
     * @notice calculates the collateral asset amount from the number of contracts
     * @param isCall option type, true if call option
     * @param underlyingDecimals decimal precision of the underlying asset
     * @param baseDecimals decimal precision of the base asset
     * @param strike64x64 strike price of the option as 64x64 fixed point number
     * @return collateral asset amount
     */
    function fromContractsToCollateral(
        uint256 contracts,
        bool isCall,
        uint8 underlyingDecimals,
        uint8 baseDecimals,
        int128 strike64x64
    ) internal pure returns (uint256) {
        if (strike64x64 == 0) {
            return 0;
        }

        if (isCall) {
            return contracts;
        }

        return
            toBaseTokenAmount(
                underlyingDecimals,
                baseDecimals,
                strike64x64.mulu(contracts)
            );
    }

    /**
     * @notice calculates number of contracts from the collateral asset amount
     * @param isCall option type, true if call option
     * @param baseDecimals decimal precision of the base asset
     * @param strike64x64 strike price of the option as 64x64 fixed point number
     * @return number of contracts
     */
    function fromCollateralToContracts(
        uint256 collateral,
        bool isCall,
        uint8 baseDecimals,
        int128 strike64x64
    ) internal pure returns (uint256) {
        if (strike64x64 == 0) {
            return 0;
        }

        if (isCall) {
            return collateral;
        }

        int128 collateral64x64 = collateral.fromDecimals(baseDecimals);
        return collateral64x64.div(strike64x64).toDecimals(baseDecimals);
    }
}

File 17 of 46 : IPremiaPool.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IPremiaPool {
    struct PoolSettings {
        address underlying;
        address base;
        address underlyingOracle;
        address baseOracle;
    }

    /**
     * @notice query holders of given token
     * @param id token id to query
     * @return list of holder addresses
     */
    function accountsByToken(uint256 id)
        external
        view
        returns (address[] memory);

    /**
     * @notice query the balance of given token held by given address
     * @param account address to query
     * @param id token to query
     * @return token balance
     */
    function balanceOf(address account, uint256 id)
        external
        view
        returns (uint256);

    /**
     * @notice exercise option on behalf of holder
     * @param holder owner of long option tokens to exercise
     * @param longTokenId long option token id
     * @param contractSize quantity of tokens to exercise
     */
    function exerciseFrom(
        address holder,
        uint256 longTokenId,
        uint256 contractSize
    ) external;

    /**
     * @notice get fundamental pool attributes
     * @return structured PoolSettings
     */
    function getPoolSettings() external view returns (PoolSettings memory);

    /**
     * @notice get first oracle price update after timestamp. If no update has been registered yet,
     * return current price feed spot price
     * @param timestamp timestamp to query
     * @return spot64x64 64x64 fixed point representation of price
     */
    function getPriceAfter64x64(uint256 timestamp)
        external
        view
        returns (int128 spot64x64);

    /**
     * @notice process expired option, freeing liquidity and distributing profits
     * @param longTokenId long option token id
     * @param contractSize quantity of tokens to process
     */
    function processExpired(uint256 longTokenId, uint256 contractSize) external;

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @notice set timestamp after which reinvestment is disabled
     * @param timestamp timestamp to begin divestment
     * @param isCallPool whether we set divestment timestamp for the call pool or put pool
     */
    function setDivestmentTimestamp(uint64 timestamp, bool isCallPool) external;

    /**
     * @notice query tokens held by given address
     * @param account address to query
     * @return list of token ids
     */
    function tokensByAccount(address account)
        external
        view
        returns (uint256[] memory);

    /**
     * @notice force update of oracle price and pending deposit pool
     */
    function update() external;

    /**
     * @notice redeem pool share tokens for underlying asset
     * @param amount quantity of share tokens to redeem
     * @param isCallPool whether to deposit underlying in the call pool or base in the put pool
     */
    function withdraw(uint256 amount, bool isCallPool) external;

    /**
     * @notice write option without using liquidity from the pool on behalf of another address
     * @param underwriter underwriter of the option from who collateral will be deposited
     * @param longReceiver address who will receive the long token (Can be the underwriter)
     * @param maturity timestamp of option maturity
     * @param strike64x64 64x64 fixed point representation of strike price
     * @param contractSize quantity of option contract tokens to write
     * @param isCall whether this is a call or a put
     * @return longTokenId token id of the long call
     * @return shortTokenId token id of the short option
     */
    function writeFrom(
        address underwriter,
        address longReceiver,
        uint64 maturity,
        int128 strike64x64,
        uint256 contractSize,
        bool isCall
    ) external payable returns (uint256 longTokenId, uint256 shortTokenId);
}

File 18 of 46 : IVault.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../vendor/IPremiaPool.sol";

import "./IVaultAdmin.sol";
import "./IVaultBase.sol";
import "./IVaultEvents.sol";
import "./IVaultView.sol";

/**
 * @title Knox Vault Interface
 */

interface IVault is IVaultAdmin, IVaultBase, IVaultEvents, IVaultView {
    /**
     * @notice gets the collateral asset ERC20 interface
     * @return ERC20 interface
     */
    function ERC20() external view returns (IERC20);

    /**
     * @notice gets the pool interface
     * @return pool interface
     */
    function Pool() external view returns (IPremiaPool);
}

File 19 of 46 : AuctionStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@solidstate/contracts/utils/EnumerableSet.sol";

import "../pricer/IPricer.sol";

import "../vendor/IExchangeHelper.sol";

import "./OrderBook.sol";

/**
 * @title Knox Dutch Auction Diamond Storage Library
 */

library AuctionStorage {
    using OrderBook for OrderBook.Index;

    struct InitAuction {
        uint64 epoch;
        uint64 expiry;
        int128 strike64x64;
        uint256 longTokenId;
        uint256 startTime;
        uint256 endTime;
    }

    enum Status {UNINITIALIZED, INITIALIZED, FINALIZED, PROCESSED, CANCELLED}

    struct Auction {
        // status of the auction
        Status status;
        // option expiration timestamp
        uint64 expiry;
        // option strike price
        int128 strike64x64;
        // auction max price
        int128 maxPrice64x64;
        // auction min price
        int128 minPrice64x64;
        // last price paid during the auction
        int128 lastPrice64x64;
        // auction start timestamp
        uint256 startTime;
        // auction end timestamp
        uint256 endTime;
        // auction processed timestamp
        uint256 processedTime;
        // total contracts available
        uint256 totalContracts;
        // total contracts sold
        uint256 totalContractsSold;
        // total unclaimed contracts
        uint256 totalUnclaimedContracts;
        // total premiums collected
        uint256 totalPremiums;
        // option long token id
        uint256 longTokenId;
    }

    struct Layout {
        // percent offset from delta strike
        int128 deltaOffset64x64;
        // minimum order size
        uint256 minSize;
        // mapping of auctions to epoch id (epoch id -> auction)
        mapping(uint64 => Auction) auctions;
        // mapping of order books to epoch id (epoch id -> order book)
        mapping(uint64 => OrderBook.Index) orderbooks;
        // mapping of unique order ids (uoids) to buyer addresses (buyer -> uoid)
        mapping(address => EnumerableSet.UintSet) uoids;
        // ExchangeHelper contract interface
        IExchangeHelper Exchange;
        // Pricer contract interface
        IPricer Pricer;
    }

    bytes32 internal constant STORAGE_SLOT =
        keccak256("knox.contracts.storage.Auction");

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }

    /************************************************
     *  VIEW
     ***********************************************/

    /**
     * @notice returns the auction parameters
     * @param epoch epoch id
     * @return auction parameters
     */
    function _getAuction(uint64 epoch) internal view returns (Auction memory) {
        return layout().auctions[epoch];
    }

    /**
     * @notice returns percent delta offset
     * @return percent delta offset as a 64x64 fixed point number
     */
    function _getDeltaOffset64x64() internal view returns (int128) {
        return layout().deltaOffset64x64;
    }

    /**
     * @notice returns the minimum order size
     * @return minimum order size
     */
    function _getMinSize() internal view returns (uint256) {
        return layout().minSize;
    }

    /**
     * @notice returns the order from the auction orderbook
     * @param epoch epoch id
     * @param orderId order id
     * @return order from auction orderbook
     */
    function _getOrderById(uint64 epoch, uint128 orderId)
        internal
        view
        returns (OrderBook.Data memory)
    {
        OrderBook.Index storage orderbook = layout().orderbooks[epoch];
        return orderbook._getOrderById(orderId);
    }

    /**
     * @notice returns the status of the auction
     * @param epoch epoch id
     * @return auction status
     */
    function _getStatus(uint64 epoch)
        internal
        view
        returns (AuctionStorage.Status)
    {
        return layout().auctions[epoch].status;
    }

    /**
     * @notice returns the stored total number of contracts that can be sold during the auction
     * returns 0 if the auction has not started
     * @param epoch epoch id
     * @return total number of contracts which may be sold
     */
    function _getTotalContracts(uint64 epoch) internal view returns (uint256) {
        return layout().auctions[epoch].totalContracts;
    }

    /**
     * @notice returns the total number of contracts sold
     * @param epoch epoch id
     * @return total number of contracts sold
     */
    function _getTotalContractsSold(uint64 epoch)
        internal
        view
        returns (uint256)
    {
        return layout().auctions[epoch].totalContractsSold;
    }

    /************************************************
     * HELPERS
     ***********************************************/

    /**
     * @notice calculates the unique order id
     * @param epoch epoch id
     * @param orderId order id
     * @return unique order id
     */
    function _formatUniqueOrderId(uint64 epoch, uint128 orderId)
        internal
        view
        returns (uint256)
    {
        // uses the first 8 bytes of the contract address to salt uoid
        bytes8 salt = bytes8(bytes20(address(this)));
        return
            (uint256(uint64(salt)) << 192) +
            (uint256(epoch) << 128) +
            uint256(orderId);
    }

    /**
     * @notice derives salt, epoch id, and order id from the unique order id
     * @param uoid unique order id
     * @return salt
     * @return epoch id
     * @return order id
     */
    function _parseUniqueOrderId(uint256 uoid)
        internal
        pure
        returns (
            bytes8,
            uint64,
            uint128
        )
    {
        uint64 salt;
        uint64 epoch;
        uint128 orderId;

        assembly {
            salt := shr(192, uoid)
            epoch := shr(128, uoid)
            orderId := uoid
        }

        return (bytes8(salt), epoch, orderId);
    }
}

File 20 of 46 : IAuctionEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./AuctionStorage.sol";

/**
 * @title Knox Auction Events Interface
 */

interface IAuctionEvents {
    /**
     * @notice emitted when the auction max/min prices have been set
     * @param epoch epoch id
     * @param strike64x64 strike price as a 64x64 fixed point number
     * @param offsetStrike64x64 offset strike price as a 64x64 fixed point number
     * @param spot64x64 spot price as a 64x64 fixed point number
     * @param maxPrice64x64 max price as a 64x64 fixed point number
     * @param minPrice64x64 min price as a 64x64 fixed point number
     */
    event AuctionPricesSet(
        uint64 indexed epoch,
        int128 strike64x64,
        int128 offsetStrike64x64,
        int128 spot64x64,
        int128 maxPrice64x64,
        int128 minPrice64x64
    );

    /**
     * @notice emitted when the exchange auction status is updated
     * @param epoch epoch id
     * @param status auction status
     */
    event AuctionStatusSet(uint64 indexed epoch, AuctionStorage.Status status);

    /**
     * @notice emitted when the delta offset is updated
     * @param oldDeltaOffset previous delta offset
     * @param newDeltaOffset new delta offset
     * @param caller address of admin
     */
    event DeltaOffsetSet(
        int128 oldDeltaOffset,
        int128 newDeltaOffset,
        address caller
    );

    /**
     * @notice emitted when the exchange helper contract address is updated
     * @param oldExchangeHelper previous exchange helper address
     * @param newExchangeHelper new exchange helper address
     * @param caller address of admin
     */
    event ExchangeHelperSet(
        address oldExchangeHelper,
        address newExchangeHelper,
        address caller
    );

    /**
     * @notice emitted when an external function reverts
     * @param message error message
     */
    event Log(string message);

    /**
     * @notice emitted when the minimum order size is updated
     * @param oldMinSize previous minimum order size
     * @param newMinSize new minimum order size
     * @param caller address of admin
     */
    event MinSizeSet(uint256 oldMinSize, uint256 newMinSize, address caller);

    /**
     * @notice emitted when a market or limit order has been placed
     * @param epoch epoch id
     * @param orderId order id
     * @param buyer address of buyer
     * @param price64x64 price paid as a 64x64 fixed point number
     * @param size quantity of options purchased
     * @param isLimitOrder true if order is a limit order
     */
    event OrderAdded(
        uint64 indexed epoch,
        uint128 orderId,
        address buyer,
        int128 price64x64,
        uint256 size,
        bool isLimitOrder
    );

    /**
     * @notice emitted when a limit order has been cancelled
     * @param epoch epoch id
     * @param orderId order id
     * @param buyer address of buyer
     */
    event OrderCanceled(uint64 indexed epoch, uint128 orderId, address buyer);

    /**
     * @notice emitted when an order (filled or unfilled) is withdrawn
     * @param epoch epoch id
     * @param buyer address of buyer
     * @param refund amount sent back to the buyer as a result of an overpayment
     * @param fill amount in long token contracts sent to the buyer
     */
    event OrderWithdrawn(
        uint64 indexed epoch,
        address buyer,
        uint256 refund,
        uint256 fill
    );

    /**
     * @notice emitted when the pricer contract address is updated
     * @param oldPricer previous pricer address
     * @param newPricer new pricer address
     * @param caller address of admin
     */
    event PricerSet(address oldPricer, address newPricer, address caller);
}

File 21 of 46 : IOwnableInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IERC173Internal } from '../IERC173Internal.sol';

interface IOwnableInternal is IERC173Internal {}

File 22 of 46 : OwnableStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

library OwnableStorage {
    struct Layout {
        address owner;
    }

    bytes32 internal constant STORAGE_SLOT =
        keccak256('solidstate.contracts.storage.Ownable');

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }

    function setOwner(Layout storage l, address owner) internal {
        l.owner = owner;
    }
}

File 23 of 46 : IERC173Internal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title Partial ERC173 interface needed by internal functions
 */
interface IERC173Internal {
    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );
}

File 24 of 46 : IERC1155Internal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IERC165 } from '../../introspection/IERC165.sol';

/**
 * @title Partial ERC1155 interface needed by internal functions
 */
interface IERC1155Internal {
    event TransferSingle(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256 id,
        uint256 value
    );

    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    event ApprovalForAll(
        address indexed account,
        address indexed operator,
        bool approved
    );
}

File 25 of 46 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title ERC165 interface registration interface
 * @dev see https://eips.ethereum.org/EIPS/eip-165
 */
interface IERC165 {
    /**
     * @notice query whether contract has registered support for given interface
     * @param interfaceId interface id
     * @return bool whether interface is supported
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 26 of 46 : IERC20Internal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title Partial ERC20 interface needed by internal functions
 */
interface IERC20Internal {
    event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );
}

File 27 of 46 : AddressUtils.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { UintUtils } from './UintUtils.sol';

library AddressUtils {
    using UintUtils for uint256;

    function toString(address account) internal pure returns (string memory) {
        return uint256(uint160(account)).toHexString(20);
    }

    function isContract(address account) internal view returns (bool) {
        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

    function sendValue(address payable account, uint256 amount) internal {
        (bool success, ) = account.call{ value: amount }('');
        require(success, 'AddressUtils: failed to send value');
    }

    function functionCall(address target, bytes memory data)
        internal
        returns (bytes memory)
    {
        return
            functionCall(target, data, 'AddressUtils: failed low-level call');
    }

    function functionCall(
        address target,
        bytes memory data,
        string memory error
    ) internal returns (bytes memory) {
        return _functionCallWithValue(target, data, 0, error);
    }

    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return
            functionCallWithValue(
                target,
                data,
                value,
                'AddressUtils: failed low-level call with value'
            );
    }

    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory error
    ) internal returns (bytes memory) {
        require(
            address(this).balance >= value,
            'AddressUtils: insufficient balance for call'
        );
        return _functionCallWithValue(target, data, value, error);
    }

    function _functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory error
    ) private returns (bytes memory) {
        require(
            isContract(target),
            'AddressUtils: function call to non-contract'
        );

        (bool success, bytes memory returnData) = target.call{ value: value }(
            data
        );

        if (success) {
            return returnData;
        } else if (returnData.length > 0) {
            assembly {
                let returnData_size := mload(returnData)
                revert(add(32, returnData), returnData_size)
            }
        } else {
            revert(error);
        }
    }
}

File 28 of 46 : UintUtils.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title utility functions for uint256 operations
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license)
 */
library UintUtils {
    bytes16 private constant HEX_SYMBOLS = '0123456789abcdef';

    function toString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return '0';
        }

        uint256 temp = value;
        uint256 digits;

        while (temp != 0) {
            digits++;
            temp /= 10;
        }

        bytes memory buffer = new bytes(digits);

        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }

        return string(buffer);
    }

    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return '0x00';
        }

        uint256 length = 0;

        for (uint256 temp = value; temp != 0; temp >>= 8) {
            unchecked {
                length++;
            }
        }

        return toHexString(value, length);
    }

    function toHexString(uint256 value, uint256 length)
        internal
        pure
        returns (string memory)
    {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = '0';
        buffer[1] = 'x';

        unchecked {
            for (uint256 i = 2 * length + 1; i > 1; --i) {
                buffer[i] = HEX_SYMBOLS[value & 0xf];
                value >>= 4;
            }
        }

        require(value == 0, 'UintUtils: hex length insufficient');

        return string(buffer);
    }
}

File 29 of 46 : ABDKMath64x64.sol
// SPDX-License-Identifier: BSD-4-Clause
/*
 * ABDK Math 64.64 Smart Contract Library.  Copyright © 2019 by ABDK Consulting.
 * Author: Mikhail Vladimirov <[email protected]>
 */
pragma solidity ^0.8.0;

/**
 * Smart contract library of mathematical functions operating with signed
 * 64.64-bit fixed point numbers.  Signed 64.64-bit fixed point number is
 * basically a simple fraction whose numerator is signed 128-bit integer and
 * denominator is 2^64.  As long as denominator is always the same, there is no
 * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are
 * represented by int128 type holding only the numerator.
 */
library ABDKMath64x64 {
  /*
   * Minimum value signed 64.64-bit fixed point number may have. 
   */
  int128 private constant MIN_64x64 = -0x80000000000000000000000000000000;

  /*
   * Maximum value signed 64.64-bit fixed point number may have. 
   */
  int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

  /**
   * Convert signed 256-bit integer number into signed 64.64-bit fixed point
   * number.  Revert on overflow.
   *
   * @param x signed 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function fromInt (int256 x) internal pure returns (int128) {
    unchecked {
      require (x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF);
      return int128 (x << 64);
    }
  }

  /**
   * Convert signed 64.64 fixed point number into signed 64-bit integer number
   * rounding down.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64-bit integer number
   */
  function toInt (int128 x) internal pure returns (int64) {
    unchecked {
      return int64 (x >> 64);
    }
  }

  /**
   * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point
   * number.  Revert on overflow.
   *
   * @param x unsigned 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function fromUInt (uint256 x) internal pure returns (int128) {
    unchecked {
      require (x <= 0x7FFFFFFFFFFFFFFF);
      return int128 (int256 (x << 64));
    }
  }

  /**
   * Convert signed 64.64 fixed point number into unsigned 64-bit integer
   * number rounding down.  Revert on underflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return unsigned 64-bit integer number
   */
  function toUInt (int128 x) internal pure returns (uint64) {
    unchecked {
      require (x >= 0);
      return uint64 (uint128 (x >> 64));
    }
  }

  /**
   * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point
   * number rounding down.  Revert on overflow.
   *
   * @param x signed 128.128-bin fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function from128x128 (int256 x) internal pure returns (int128) {
    unchecked {
      int256 result = x >> 64;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Convert signed 64.64 fixed point number into signed 128.128 fixed point
   * number.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 128.128 fixed point number
   */
  function to128x128 (int128 x) internal pure returns (int256) {
    unchecked {
      return int256 (x) << 64;
    }
  }

  /**
   * Calculate x + y.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function add (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 result = int256(x) + y;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x - y.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function sub (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 result = int256(x) - y;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x * y rounding down.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function mul (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 result = int256(x) * y >> 64;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point
   * number and y is signed 256-bit integer number.  Revert on overflow.
   *
   * @param x signed 64.64 fixed point number
   * @param y signed 256-bit integer number
   * @return signed 256-bit integer number
   */
  function muli (int128 x, int256 y) internal pure returns (int256) {
    unchecked {
      if (x == MIN_64x64) {
        require (y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF &&
          y <= 0x1000000000000000000000000000000000000000000000000);
        return -y << 63;
      } else {
        bool negativeResult = false;
        if (x < 0) {
          x = -x;
          negativeResult = true;
        }
        if (y < 0) {
          y = -y; // We rely on overflow behavior here
          negativeResult = !negativeResult;
        }
        uint256 absoluteResult = mulu (x, uint256 (y));
        if (negativeResult) {
          require (absoluteResult <=
            0x8000000000000000000000000000000000000000000000000000000000000000);
          return -int256 (absoluteResult); // We rely on overflow behavior here
        } else {
          require (absoluteResult <=
            0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
          return int256 (absoluteResult);
        }
      }
    }
  }

  /**
   * Calculate x * y rounding down, where x is signed 64.64 fixed point number
   * and y is unsigned 256-bit integer number.  Revert on overflow.
   *
   * @param x signed 64.64 fixed point number
   * @param y unsigned 256-bit integer number
   * @return unsigned 256-bit integer number
   */
  function mulu (int128 x, uint256 y) internal pure returns (uint256) {
    unchecked {
      if (y == 0) return 0;

      require (x >= 0);

      uint256 lo = (uint256 (int256 (x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64;
      uint256 hi = uint256 (int256 (x)) * (y >> 128);

      require (hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
      hi <<= 64;

      require (hi <=
        0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo);
      return hi + lo;
    }
  }

  /**
   * Calculate x / y rounding towards zero.  Revert on overflow or when y is
   * zero.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function div (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      require (y != 0);
      int256 result = (int256 (x) << 64) / y;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x / y rounding towards zero, where x and y are signed 256-bit
   * integer numbers.  Revert on overflow or when y is zero.
   *
   * @param x signed 256-bit integer number
   * @param y signed 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function divi (int256 x, int256 y) internal pure returns (int128) {
    unchecked {
      require (y != 0);

      bool negativeResult = false;
      if (x < 0) {
        x = -x; // We rely on overflow behavior here
        negativeResult = true;
      }
      if (y < 0) {
        y = -y; // We rely on overflow behavior here
        negativeResult = !negativeResult;
      }
      uint128 absoluteResult = divuu (uint256 (x), uint256 (y));
      if (negativeResult) {
        require (absoluteResult <= 0x80000000000000000000000000000000);
        return -int128 (absoluteResult); // We rely on overflow behavior here
      } else {
        require (absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
        return int128 (absoluteResult); // We rely on overflow behavior here
      }
    }
  }

  /**
   * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
   * integer numbers.  Revert on overflow or when y is zero.
   *
   * @param x unsigned 256-bit integer number
   * @param y unsigned 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function divu (uint256 x, uint256 y) internal pure returns (int128) {
    unchecked {
      require (y != 0);
      uint128 result = divuu (x, y);
      require (result <= uint128 (MAX_64x64));
      return int128 (result);
    }
  }

  /**
   * Calculate -x.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function neg (int128 x) internal pure returns (int128) {
    unchecked {
      require (x != MIN_64x64);
      return -x;
    }
  }

  /**
   * Calculate |x|.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function abs (int128 x) internal pure returns (int128) {
    unchecked {
      require (x != MIN_64x64);
      return x < 0 ? -x : x;
    }
  }

  /**
   * Calculate 1 / x rounding towards zero.  Revert on overflow or when x is
   * zero.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function inv (int128 x) internal pure returns (int128) {
    unchecked {
      require (x != 0);
      int256 result = int256 (0x100000000000000000000000000000000) / x;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function avg (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      return int128 ((int256 (x) + int256 (y)) >> 1);
    }
  }

  /**
   * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down.
   * Revert on overflow or in case x * y is negative.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function gavg (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 m = int256 (x) * int256 (y);
      require (m >= 0);
      require (m <
          0x4000000000000000000000000000000000000000000000000000000000000000);
      return int128 (sqrtu (uint256 (m)));
    }
  }

  /**
   * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number
   * and y is unsigned 256-bit integer number.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y uint256 value
   * @return signed 64.64-bit fixed point number
   */
  function pow (int128 x, uint256 y) internal pure returns (int128) {
    unchecked {
      bool negative = x < 0 && y & 1 == 1;

      uint256 absX = uint128 (x < 0 ? -x : x);
      uint256 absResult;
      absResult = 0x100000000000000000000000000000000;

      if (absX <= 0x10000000000000000) {
        absX <<= 63;
        while (y != 0) {
          if (y & 0x1 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          if (y & 0x2 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          if (y & 0x4 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          if (y & 0x8 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          y >>= 4;
        }

        absResult >>= 64;
      } else {
        uint256 absXShift = 63;
        if (absX < 0x1000000000000000000000000) { absX <<= 32; absXShift -= 32; }
        if (absX < 0x10000000000000000000000000000) { absX <<= 16; absXShift -= 16; }
        if (absX < 0x1000000000000000000000000000000) { absX <<= 8; absXShift -= 8; }
        if (absX < 0x10000000000000000000000000000000) { absX <<= 4; absXShift -= 4; }
        if (absX < 0x40000000000000000000000000000000) { absX <<= 2; absXShift -= 2; }
        if (absX < 0x80000000000000000000000000000000) { absX <<= 1; absXShift -= 1; }

        uint256 resultShift = 0;
        while (y != 0) {
          require (absXShift < 64);

          if (y & 0x1 != 0) {
            absResult = absResult * absX >> 127;
            resultShift += absXShift;
            if (absResult > 0x100000000000000000000000000000000) {
              absResult >>= 1;
              resultShift += 1;
            }
          }
          absX = absX * absX >> 127;
          absXShift <<= 1;
          if (absX >= 0x100000000000000000000000000000000) {
              absX >>= 1;
              absXShift += 1;
          }

          y >>= 1;
        }

        require (resultShift < 64);
        absResult >>= 64 - resultShift;
      }
      int256 result = negative ? -int256 (absResult) : int256 (absResult);
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate sqrt (x) rounding down.  Revert if x < 0.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function sqrt (int128 x) internal pure returns (int128) {
    unchecked {
      require (x >= 0);
      return int128 (sqrtu (uint256 (int256 (x)) << 64));
    }
  }

  /**
   * Calculate binary logarithm of x.  Revert if x <= 0.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function log_2 (int128 x) internal pure returns (int128) {
    unchecked {
      require (x > 0);

      int256 msb = 0;
      int256 xc = x;
      if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; }
      if (xc >= 0x100000000) { xc >>= 32; msb += 32; }
      if (xc >= 0x10000) { xc >>= 16; msb += 16; }
      if (xc >= 0x100) { xc >>= 8; msb += 8; }
      if (xc >= 0x10) { xc >>= 4; msb += 4; }
      if (xc >= 0x4) { xc >>= 2; msb += 2; }
      if (xc >= 0x2) msb += 1;  // No need to shift xc anymore

      int256 result = msb - 64 << 64;
      uint256 ux = uint256 (int256 (x)) << uint256 (127 - msb);
      for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) {
        ux *= ux;
        uint256 b = ux >> 255;
        ux >>= 127 + b;
        result += bit * int256 (b);
      }

      return int128 (result);
    }
  }

  /**
   * Calculate natural logarithm of x.  Revert if x <= 0.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function ln (int128 x) internal pure returns (int128) {
    unchecked {
      require (x > 0);

      return int128 (int256 (
          uint256 (int256 (log_2 (x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF >> 128));
    }
  }

  /**
   * Calculate binary exponent of x.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function exp_2 (int128 x) internal pure returns (int128) {
    unchecked {
      require (x < 0x400000000000000000); // Overflow

      if (x < -0x400000000000000000) return 0; // Underflow

      uint256 result = 0x80000000000000000000000000000000;

      if (x & 0x8000000000000000 > 0)
        result = result * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128;
      if (x & 0x4000000000000000 > 0)
        result = result * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128;
      if (x & 0x2000000000000000 > 0)
        result = result * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128;
      if (x & 0x1000000000000000 > 0)
        result = result * 0x10B5586CF9890F6298B92B71842A98363 >> 128;
      if (x & 0x800000000000000 > 0)
        result = result * 0x1059B0D31585743AE7C548EB68CA417FD >> 128;
      if (x & 0x400000000000000 > 0)
        result = result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128;
      if (x & 0x200000000000000 > 0)
        result = result * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128;
      if (x & 0x100000000000000 > 0)
        result = result * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128;
      if (x & 0x80000000000000 > 0)
        result = result * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128;
      if (x & 0x40000000000000 > 0)
        result = result * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128;
      if (x & 0x20000000000000 > 0)
        result = result * 0x100162F3904051FA128BCA9C55C31E5DF >> 128;
      if (x & 0x10000000000000 > 0)
        result = result * 0x1000B175EFFDC76BA38E31671CA939725 >> 128;
      if (x & 0x8000000000000 > 0)
        result = result * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128;
      if (x & 0x4000000000000 > 0)
        result = result * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128;
      if (x & 0x2000000000000 > 0)
        result = result * 0x1000162E525EE054754457D5995292026 >> 128;
      if (x & 0x1000000000000 > 0)
        result = result * 0x10000B17255775C040618BF4A4ADE83FC >> 128;
      if (x & 0x800000000000 > 0)
        result = result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128;
      if (x & 0x400000000000 > 0)
        result = result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128;
      if (x & 0x200000000000 > 0)
        result = result * 0x10000162E43F4F831060E02D839A9D16D >> 128;
      if (x & 0x100000000000 > 0)
        result = result * 0x100000B1721BCFC99D9F890EA06911763 >> 128;
      if (x & 0x80000000000 > 0)
        result = result * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128;
      if (x & 0x40000000000 > 0)
        result = result * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128;
      if (x & 0x20000000000 > 0)
        result = result * 0x100000162E430E5A18F6119E3C02282A5 >> 128;
      if (x & 0x10000000000 > 0)
        result = result * 0x1000000B1721835514B86E6D96EFD1BFE >> 128;
      if (x & 0x8000000000 > 0)
        result = result * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128;
      if (x & 0x4000000000 > 0)
        result = result * 0x10000002C5C8601CC6B9E94213C72737A >> 128;
      if (x & 0x2000000000 > 0)
        result = result * 0x1000000162E42FFF037DF38AA2B219F06 >> 128;
      if (x & 0x1000000000 > 0)
        result = result * 0x10000000B17217FBA9C739AA5819F44F9 >> 128;
      if (x & 0x800000000 > 0)
        result = result * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128;
      if (x & 0x400000000 > 0)
        result = result * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128;
      if (x & 0x200000000 > 0)
        result = result * 0x10000000162E42FF0999CE3541B9FFFCF >> 128;
      if (x & 0x100000000 > 0)
        result = result * 0x100000000B17217F80F4EF5AADDA45554 >> 128;
      if (x & 0x80000000 > 0)
        result = result * 0x10000000058B90BFBF8479BD5A81B51AD >> 128;
      if (x & 0x40000000 > 0)
        result = result * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128;
      if (x & 0x20000000 > 0)
        result = result * 0x100000000162E42FEFB2FED257559BDAA >> 128;
      if (x & 0x10000000 > 0)
        result = result * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128;
      if (x & 0x8000000 > 0)
        result = result * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128;
      if (x & 0x4000000 > 0)
        result = result * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128;
      if (x & 0x2000000 > 0)
        result = result * 0x1000000000162E42FEFA494F1478FDE05 >> 128;
      if (x & 0x1000000 > 0)
        result = result * 0x10000000000B17217F7D20CF927C8E94C >> 128;
      if (x & 0x800000 > 0)
        result = result * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128;
      if (x & 0x400000 > 0)
        result = result * 0x100000000002C5C85FDF477B662B26945 >> 128;
      if (x & 0x200000 > 0)
        result = result * 0x10000000000162E42FEFA3AE53369388C >> 128;
      if (x & 0x100000 > 0)
        result = result * 0x100000000000B17217F7D1D351A389D40 >> 128;
      if (x & 0x80000 > 0)
        result = result * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128;
      if (x & 0x40000 > 0)
        result = result * 0x1000000000002C5C85FDF4741BEA6E77E >> 128;
      if (x & 0x20000 > 0)
        result = result * 0x100000000000162E42FEFA39FE95583C2 >> 128;
      if (x & 0x10000 > 0)
        result = result * 0x1000000000000B17217F7D1CFB72B45E1 >> 128;
      if (x & 0x8000 > 0)
        result = result * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128;
      if (x & 0x4000 > 0)
        result = result * 0x10000000000002C5C85FDF473E242EA38 >> 128;
      if (x & 0x2000 > 0)
        result = result * 0x1000000000000162E42FEFA39F02B772C >> 128;
      if (x & 0x1000 > 0)
        result = result * 0x10000000000000B17217F7D1CF7D83C1A >> 128;
      if (x & 0x800 > 0)
        result = result * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128;
      if (x & 0x400 > 0)
        result = result * 0x100000000000002C5C85FDF473DEA871F >> 128;
      if (x & 0x200 > 0)
        result = result * 0x10000000000000162E42FEFA39EF44D91 >> 128;
      if (x & 0x100 > 0)
        result = result * 0x100000000000000B17217F7D1CF79E949 >> 128;
      if (x & 0x80 > 0)
        result = result * 0x10000000000000058B90BFBE8E7BCE544 >> 128;
      if (x & 0x40 > 0)
        result = result * 0x1000000000000002C5C85FDF473DE6ECA >> 128;
      if (x & 0x20 > 0)
        result = result * 0x100000000000000162E42FEFA39EF366F >> 128;
      if (x & 0x10 > 0)
        result = result * 0x1000000000000000B17217F7D1CF79AFA >> 128;
      if (x & 0x8 > 0)
        result = result * 0x100000000000000058B90BFBE8E7BCD6D >> 128;
      if (x & 0x4 > 0)
        result = result * 0x10000000000000002C5C85FDF473DE6B2 >> 128;
      if (x & 0x2 > 0)
        result = result * 0x1000000000000000162E42FEFA39EF358 >> 128;
      if (x & 0x1 > 0)
        result = result * 0x10000000000000000B17217F7D1CF79AB >> 128;

      result >>= uint256 (int256 (63 - (x >> 64)));
      require (result <= uint256 (int256 (MAX_64x64)));

      return int128 (int256 (result));
    }
  }

  /**
   * Calculate natural exponent of x.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function exp (int128 x) internal pure returns (int128) {
    unchecked {
      require (x < 0x400000000000000000); // Overflow

      if (x < -0x400000000000000000) return 0; // Underflow

      return exp_2 (
          int128 (int256 (x) * 0x171547652B82FE1777D0FFDA0D23A7D12 >> 128));
    }
  }

  /**
   * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
   * integer numbers.  Revert on overflow or when y is zero.
   *
   * @param x unsigned 256-bit integer number
   * @param y unsigned 256-bit integer number
   * @return unsigned 64.64-bit fixed point number
   */
  function divuu (uint256 x, uint256 y) private pure returns (uint128) {
    unchecked {
      require (y != 0);

      uint256 result;

      if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
        result = (x << 64) / y;
      else {
        uint256 msb = 192;
        uint256 xc = x >> 192;
        if (xc >= 0x100000000) { xc >>= 32; msb += 32; }
        if (xc >= 0x10000) { xc >>= 16; msb += 16; }
        if (xc >= 0x100) { xc >>= 8; msb += 8; }
        if (xc >= 0x10) { xc >>= 4; msb += 4; }
        if (xc >= 0x4) { xc >>= 2; msb += 2; }
        if (xc >= 0x2) msb += 1;  // No need to shift xc anymore

        result = (x << 255 - msb) / ((y - 1 >> msb - 191) + 1);
        require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);

        uint256 hi = result * (y >> 128);
        uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);

        uint256 xh = x >> 192;
        uint256 xl = x << 64;

        if (xl < lo) xh -= 1;
        xl -= lo; // We rely on overflow behavior here
        lo = hi << 128;
        if (xl < lo) xh -= 1;
        xl -= lo; // We rely on overflow behavior here

        assert (xh == hi >> 128);

        result += xl / y;
      }

      require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
      return uint128 (result);
    }
  }

  /**
   * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer
   * number.
   *
   * @param x unsigned 256-bit integer number
   * @return unsigned 128-bit integer number
   */
  function sqrtu (uint256 x) private pure returns (uint128) {
    unchecked {
      if (x == 0) return 0;
      else {
        uint256 xx = x;
        uint256 r = 1;
        if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; }
        if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; }
        if (xx >= 0x100000000) { xx >>= 32; r <<= 16; }
        if (xx >= 0x10000) { xx >>= 16; r <<= 8; }
        if (xx >= 0x100) { xx >>= 8; r <<= 4; }
        if (xx >= 0x10) { xx >>= 4; r <<= 2; }
        if (xx >= 0x8) { r <<= 1; }
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1; // Seven iterations should be enough
        uint256 r1 = x / r;
        return uint128 (r < r1 ? r : r1);
      }
    }
  }
}

File 30 of 46 : ABDKMath64x64Token.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { ABDKMath64x64 } from 'abdk-libraries-solidity/ABDKMath64x64.sol';

/**
 * @title SolidState token extensions for ABDKMath64x64 library
 */
library ABDKMath64x64Token {
    using ABDKMath64x64 for int128;

    /**
     * @notice convert 64x64 fixed point representation of token amount to decimal
     * @param value64x64 64x64 fixed point representation of token amount
     * @param decimals token display decimals
     * @return value decimal representation of token amount
     */
    function toDecimals(int128 value64x64, uint8 decimals)
        internal
        pure
        returns (uint256 value)
    {
        value = value64x64.mulu(10**decimals);
    }

    /**
     * @notice convert decimal representation of token amount to 64x64 fixed point
     * @param value decimal representation of token amount
     * @param decimals token display decimals
     * @return value64x64 64x64 fixed point representation of token amount
     */
    function fromDecimals(uint256 value, uint8 decimals)
        internal
        pure
        returns (int128 value64x64)
    {
        value64x64 = ABDKMath64x64.divu(value, 10**decimals);
    }

    /**
     * @notice convert 64x64 fixed point representation of token amount to wei (18 decimals)
     * @param value64x64 64x64 fixed point representation of token amount
     * @return value wei representation of token amount
     */
    function toWei(int128 value64x64) internal pure returns (uint256 value) {
        value = toDecimals(value64x64, 18);
    }

    /**
     * @notice convert wei representation (18 decimals) of token amount to 64x64 fixed point
     * @param value wei representation of token amount
     * @return value64x64 64x64 fixed point representation of token amount
     */
    function fromWei(uint256 value) internal pure returns (int128 value64x64) {
        value64x64 = fromDecimals(value, 18);
    }
}

File 31 of 46 : IVaultAdmin.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./VaultStorage.sol";

/**
 * @title Knox Vault Admin Interface
 */

interface IVaultAdmin {
    /************************************************
     *  ADMIN
     ***********************************************/

    /**
     * @notice sets the new auction
     * @dev the auction contract address must be set during the vault initialization
     * @param newAuction address of the new auction
     */
    function setAuction(address newAuction) external;

    /**
     * @notice sets the start and end offsets for the auction
     * @param newStartOffset new start offset
     * @param newEndOffset new end offset
     */
    function setAuctionWindowOffsets(
        uint256 newStartOffset,
        uint256 newEndOffset
    ) external;

    /**
     * @notice sets the option delta value
     * @param newDelta64x64 new option delta value as a 64x64 fixed point number
     */
    function setDelta64x64(int128 newDelta64x64) external;

    /**
     * @notice sets the new fee recipient
     * @param newFeeRecipient address of the new fee recipient
     */
    function setFeeRecipient(address newFeeRecipient) external;

    /**
     * @notice sets the new keeper
     * @param newKeeper address of the new keeper
     */
    function setKeeper(address newKeeper) external;

    /**
     * @notice sets the new pricer
     * @dev the pricer contract address must be set during the vault initialization
     * @param newPricer address of the new pricer
     */
    function setPricer(address newPricer) external;

    /**
     * @notice sets the new queue
     * @dev the queue contract address must be set during the vault initialization
     * @param newQueue address of the new queue
     */
    function setQueue(address newQueue) external;

    /**
     * @notice sets the performance fee for the vault
     * @param newPerformanceFee64x64 performance fee as a 64x64 fixed point number
     */
    function setPerformanceFee64x64(int128 newPerformanceFee64x64) external;

    /************************************************
     *  INITIALIZE AUCTION
     ***********************************************/

    /**
     * @notice sets the option parameters which will be sold, then initializes the auction
     */
    function initializeAuction() external;

    /************************************************
     *  INITIALIZE EPOCH
     ***********************************************/

    /**
     * @notice collects performance fee from epoch income, processes the queued deposits,
     * increments the epoch id, then sets the auction prices
     * @dev it assumed that an auction has already been initialized
     */
    function initializeEpoch() external;

    /************************************************
     *  PROCESS AUCTION
     ***********************************************/

    /**
     * @notice processes the auction when it has been finalized or cancelled
     * @dev it assumed that an auction has already been initialized and the auction prices
     * have been set
     */
    function processAuction() external;
}

File 32 of 46 : IVaultBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@solidstate/contracts/token/ERC20/metadata/IERC20Metadata.sol";
import "@solidstate/contracts/token/ERC4626/IERC4626.sol";
import "@solidstate/contracts/utils/IMulticall.sol";

/**
 * @title Knox Vault Base Interface
 * @dev includes ERC20Metadata and ERC4626 interfaces
 */

interface IVaultBase is IERC20Metadata, IERC4626, IMulticall {

}

File 33 of 46 : IVaultEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title Knox Vault Events Interface
 */

interface IVaultEvents {
    /**
     * @notice emitted when the auction contract address is updated
     * @param epoch epoch id
     * @param oldAuction previous auction address
     * @param newAuction new auction address
     * @param caller address of admin
     */
    event AuctionSet(
        uint64 indexed epoch,
        address oldAuction,
        address newAuction,
        address caller
    );

    /**
     * @notice emitted when the is processed
     * @param epoch epoch id
     * @param totalCollateralUsed contracts sold, denominated in the collateral asset
     * @param totalContractsSold contracts sold during the auction
     * @param totalPremiums premiums earned during the auction
     */
    event AuctionProcessed(
        uint64 indexed epoch,
        uint256 totalCollateralUsed,
        uint256 totalContractsSold,
        uint256 totalPremiums
    );

    /**
     * @notice emitted when the auction offset window is updated
     * @param epoch epoch id
     * @param oldStartOffset previous start offset
     * @param newStartOffset new start offset
     * @param oldEndOffset previous end offset
     * @param newEndOffset new end offset
     * @param caller address of admin
     */
    event AuctionWindowOffsetsSet(
        uint64 indexed epoch,
        uint256 oldStartOffset,
        uint256 newStartOffset,
        uint256 oldEndOffset,
        uint256 newEndOffset,
        address caller
    );

    /**
     * @notice emitted when the option delta is updated
     * @param epoch epoch id
     * @param oldDelta previous option delta
     * @param newDelta new option delta
     * @param caller address of admin
     */
    event DeltaSet(
        uint64 indexed epoch,
        int128 oldDelta,
        int128 newDelta,
        address caller
    );

    /**
     * @notice emitted when a distribution is sent to a liquidity provider
     * @param epoch epoch id
     * @param collateralAmount quantity of collateral distributed to the receiver
     * @param shortContracts quantity of short contracts distributed to the receiver
     * @param receiver address of the receiver
     */
    event DistributionSent(
        uint64 indexed epoch,
        uint256 collateralAmount,
        uint256 shortContracts,
        address receiver
    );

    /**
     * @notice emitted when the fee recipient address is updated
     * @param epoch epoch id
     * @param oldFeeRecipient previous fee recipient address
     * @param newFeeRecipient new fee recipient address
     * @param caller address of admin
     */
    event FeeRecipientSet(
        uint64 indexed epoch,
        address oldFeeRecipient,
        address newFeeRecipient,
        address caller
    );

    /**
     * @notice emitted when the keeper address is updated
     * @param epoch epoch id
     * @param oldKeeper previous keeper address
     * @param newKeeper new keeper address
     * @param caller address of admin
     */
    event KeeperSet(
        uint64 indexed epoch,
        address oldKeeper,
        address newKeeper,
        address caller
    );

    /**
     * @notice emitted when an external function reverts
     * @param message error message
     */
    event Log(string message);

    /**
     * @notice emitted when option parameters are set
     * @param epoch epoch id
     * @param expiry expiration timestamp
     * @param strike64x64 strike price as a 64x64 fixed point number
     * @param longTokenId long token id
     * @param shortTokenId short token id
     */
    event OptionParametersSet(
        uint64 indexed epoch,
        uint64 expiry,
        int128 strike64x64,
        uint256 longTokenId,
        uint256 shortTokenId
    );

    /**
     * @notice emitted when the performance fee is collected
     * @param epoch epoch id
     * @param gain amount earned during the epoch
     * @param loss amount lost during the epoch
     * @param feeInCollateral fee from net income, denominated in the collateral asset
     */
    event PerformanceFeeCollected(
        uint64 indexed epoch,
        uint256 gain,
        uint256 loss,
        uint256 feeInCollateral
    );

    /**
     * @notice emitted when the performance fee is updated
     * @param epoch epoch id
     * @param oldPerformanceFee previous performance fee
     * @param newPerformanceFee new performance fee
     * @param caller address of admin
     */
    event PerformanceFeeSet(
        uint64 indexed epoch,
        int128 oldPerformanceFee,
        int128 newPerformanceFee,
        address caller
    );

    /**
     * @notice emitted when the pricer contract address is updated
     * @param epoch epoch id
     * @param oldPricer previous pricer address
     * @param newPricer new pricer address
     * @param caller address of admin
     */
    event PricerSet(
        uint64 indexed epoch,
        address oldPricer,
        address newPricer,
        address caller
    );

    /**
     * @notice emitted when the queue contract address is updated
     * @param epoch epoch id
     * @param oldQueue previous queue address
     * @param newQueue new queue address
     * @param caller address of admin
     */
    event QueueSet(
        uint64 indexed epoch,
        address oldQueue,
        address newQueue,
        address caller
    );

    /**
     * @notice emitted when the reserved liquidity is withdrawn from the pool
     * @param epoch epoch id
     * @param amount quantity of reserved liquidity removed from pool
     */
    event ReservedLiquidityWithdrawn(uint64 indexed epoch, uint256 amount);
}

File 34 of 46 : IVaultView.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./VaultStorage.sol";

/**
 * @title Knox Vault View Interface
 */

interface IVaultView {
    /************************************************
     *  VIEW
     ***********************************************/

    /**
     * @notice returns the address of assigned actors
     * @return address of owner
     * @return address of fee recipient
     * @return address of keeper
     */
    function getActors()
        external
        view
        returns (
            address,
            address,
            address
        );

    /**
     * @notice returns the auction window offsets
     * @return start offset
     * @return end offset
     */
    function getAuctionWindowOffsets() external view returns (uint256, uint256);

    /**
     * @notice returns the address of connected services
     * @return address of Auction
     * @return address of Premia Pool
     * @return address of Pricer
     * @return address of Queue
     */
    function getConnections()
        external
        view
        returns (
            address,
            address,
            address,
            address
        );

    /**
     * @notice returns option delta
     * @return option delta as a 64x64 fixed point number
     */
    function getDelta64x64() external view returns (int128);

    /**
     * @notice returns the current epoch
     * @return current epoch id
     */
    function getEpoch() external view returns (uint64);

    /**
     * @notice returns the option by epoch id
     * @return option parameters
     */
    function getOption(uint64 epoch)
        external
        view
        returns (VaultStorage.Option memory);

    /**
     * @notice returns option type (call/put)
     * @return true if opton is a call
     */
    function getOptionType() external view returns (bool);

    /**
     * @notice returns performance fee
     * @return performance fee as a 64x64 fixed point number
     */
    function getPerformanceFee64x64() external view returns (int128);

    /**
     * @notice returns the total amount of collateral and short contracts to distribute
     * @param assetAmount quantity of assets to withdraw
     * @return distribution amount in collateral asset
     * @return distribution amount in the short contracts
     */
    function previewDistributions(uint256 assetAmount)
        external
        view
        returns (uint256, uint256);

    /**
     * @notice estimates the total reserved "active" collateral
     * @dev collateral is reserved from the auction to ensure the Vault has sufficent funds to
     * cover the APY fee
     * @return estimated amount of reserved "active" collateral
     */
    function previewReserves() external view returns (uint256);

    /**
     * @notice estimates the total number of contracts from the collateral and reserves held by the vault
     * @param strike64x64 strike price of the option as 64x64 fixed point number
     * @param collateral amount of collateral held by vault
     * @param reserves amount of reserves held by vault
     * @return estimated number of contracts
     */
    function previewTotalContracts(
        int128 strike64x64,
        uint256 collateral,
        uint256 reserves
    ) external view returns (uint256);

    /**
     * @notice calculates the total active vault by deducting the premiums from the ERC20 balance
     * @return total active collateral
     */
    function totalCollateral() external view returns (uint256);

    /**
     * @notice calculates the short position value denominated in the collateral asset
     * @return total short position in collateral amount
     */
    function totalShortAsCollateral() external view returns (uint256);

    /**
     * @notice returns the amount in short contracts underwitten by the vault
     * @return total short contracts
     */
    function totalShortAsContracts() external view returns (uint256);
}

File 35 of 46 : VaultStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../auction/IAuction.sol";

import "../pricer/IPricer.sol";

import "../queue/IQueue.sol";

/**
 * @title Knox Vault Diamond Storage Library
 */

library VaultStorage {
    struct InitProxy {
        bool isCall;
        int128 delta64x64;
        int128 reserveRate64x64;
        int128 performanceFee64x64;
        string name;
        string symbol;
        address keeper;
        address feeRecipient;
        address pricer;
        address pool;
    }

    struct InitImpl {
        address auction;
        address queue;
        address pricer;
    }

    struct Option {
        // option expiration timestamp
        uint64 expiry;
        // option strike price
        int128 strike64x64;
        // option long token id
        uint256 longTokenId;
        // option short token id
        uint256 shortTokenId;
    }

    struct Layout {
        // base asset decimals
        uint8 baseDecimals;
        // underlying asset decimals
        uint8 underlyingDecimals;
        // option type, true if option is a call
        bool isCall;
        // auction processing flag, true if auction has been processed
        bool auctionProcessed;
        // vault option delta
        int128 delta64x64;
        // mapping of options to epoch id (epoch id -> option)
        mapping(uint64 => Option) options;
        // epoch id
        uint64 epoch;
        // auction start offset in seconds (startOffset = startTime - expiry)
        uint256 startOffset;
        // auction end offset in seconds (endOffset = endTime - expiry)
        uint256 endOffset;
        // auction start timestamp
        uint256 startTime;
        // total asset amount withdrawn during an epoch
        uint256 totalWithdrawals;
        // total asset amount not including premiums collected from the auction
        uint256 lastTotalAssets;
        // total premium collected during the auction
        uint256 totalPremium;
        // performance fee collected during epoch initialization
        uint256 fee;
        // percentage of asset to be held as reserves
        int128 reserveRate64x64;
        // percentage of fees taken from net income
        int128 performanceFee64x64;
        // fee recipient address
        address feeRecipient;
        // keeper bot address
        address keeper;
        // Auction contract interface
        IAuction Auction;
        // Queue contract interface
        IQueue Queue;
        // Pricer contract interface
        IPricer Pricer;
    }

    bytes32 internal constant LAYOUT_SLOT =
        keccak256("knox.contracts.storage.Vault");

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = LAYOUT_SLOT;
        assembly {
            l.slot := slot
        }
    }

    /************************************************
     *  VIEW
     ***********************************************/

    /**
     * @notice returns the current epoch
     * @return current epoch id
     */
    function _getEpoch() internal view returns (uint64) {
        return layout().epoch;
    }

    /**
     * @notice returns the option by epoch id
     * @return option parameters
     */
    function _getOption(uint64 epoch) internal view returns (Option memory) {
        return layout().options[epoch];
    }
}

File 36 of 46 : IPricer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

/**
 * @title Knox Pricer Interface
 */

interface IPricer {
    /**
     * @notice gets the latest price of the underlying denominated in the base
     * @return price of underlying asset as 64x64 fixed point number
     */
    function latestAnswer64x64() external view returns (int128);

    /**
     * @notice calculates the time remaining until maturity
     * @param expiry the expiry date as UNIX timestamp
     * @return time remaining until maturity
     */
    function getTimeToMaturity64x64(uint64 expiry)
        external
        view
        returns (int128);

    /**
     * @notice gets the annualized volatility of the pool pair
     * @param spot64x64 spot price of the underlying as 64x64 fixed point number
     * @param strike64x64 strike price of the option as 64x64 fixed point number
     * @param timeToMaturity64x64 time remaining until maturity as a 64x64 fixed point number
     * @return annualized volatility as 64x64 fixed point number
     */
    function getAnnualizedVolatility64x64(
        int128 spot64x64,
        int128 strike64x64,
        int128 timeToMaturity64x64
    ) external view returns (int128);

    /**
     * @notice gets the option price using the Black-Scholes model
     * @param spot64x64 spot price of the underlying as 64x64 fixed point number
     * @param strike64x64 strike price of the option as 64x64 fixed point number
     * @param timeToMaturity64x64 time remaining until maturity as a 64x64 fixed point number
     * @param isCall option type, true if call option
     * @return price of the option denominated in the base as 64x64 fixed point number
     */
    function getBlackScholesPrice64x64(
        int128 spot64x64,
        int128 strike64x64,
        int128 timeToMaturity64x64,
        bool isCall
    ) external view returns (int128);

    /**
     * @notice calculates the delta strike price
     * @param isCall option type, true if call option
     * @param expiry the expiry date as UNIX timestamp
     * @param delta64x64 option delta as 64x64 fixed point number
     * @return delta strike price as 64x64 fixed point number
     */
    function getDeltaStrikePrice64x64(
        bool isCall,
        uint64 expiry,
        int128 delta64x64
    ) external view returns (int128);

    /**
     * @notice rounds a value to the floor or ceiling depending on option type
     * @param isCall option type, true if call option
     * @param n input value
     * @return rounded value as 64x64 fixed point number
     */
    function snapToGrid64x64(bool isCall, int128 n)
        external
        view
        returns (int128);
}

File 37 of 46 : IQueue.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@solidstate/contracts/introspection/IERC165.sol";
import "@solidstate/contracts/token/ERC1155/IERC1155.sol";
import "@solidstate/contracts/token/ERC1155/enumerable/IERC1155Enumerable.sol";
import "@solidstate/contracts/utils/IMulticall.sol";

import "../vendor/IExchangeHelper.sol";

import "./IQueueEvents.sol";

/**
 * @title Knox Queue Interface
 */

interface IQueue is
    IERC165,
    IERC1155,
    IERC1155Enumerable,
    IMulticall,
    IQueueEvents
{
    /************************************************
     *  ADMIN
     ***********************************************/

    /**
     * @notice sets a new max TVL for deposits
     * @param newMaxTVL is the new TVL limit for deposits
     */
    function setMaxTVL(uint256 newMaxTVL) external;

    /**
     * @notice sets a new Exchange Helper contract
     * @param newExchangeHelper is the new Exchange Helper contract address
     */
    function setExchangeHelper(address newExchangeHelper) external;

    /************************************************
     *  DEPOSIT
     ***********************************************/

    /**
     * @notice deposits collateral asset
     * @dev sent ETH will be wrapped as wETH, sender must approve contract
     * @param amount total collateral deposited
     */
    function deposit(uint256 amount) external payable;

    /**
     * @notice swaps into the collateral asset and deposits the proceeds
     * @dev sent ETH will be wrapped as wETH, sender must approve contract
     * @param s swap arguments
     */
    function swapAndDeposit(IExchangeHelper.SwapArgs calldata s)
        external
        payable;

    /************************************************
     *  CANCEL
     ***********************************************/

    /**
     * @notice cancels deposit, refunds collateral asset
     * @dev cancellation must be made within the same epoch as the deposit
     * @param amount total collateral which will be withdrawn
     */
    function cancel(uint256 amount) external;

    /************************************************
     *  REDEEM
     ***********************************************/

    /**
     * @notice exchanges claim token for vault shares
     * @param tokenId claim token id
     */
    function redeem(uint256 tokenId) external;

    /**
     * @notice exchanges claim token for vault shares
     * @param tokenId claim token id
     * @param receiver vault share recipient
     */
    function redeem(uint256 tokenId, address receiver) external;

    /**
     * @notice exchanges claim token for vault shares
     * @param tokenId claim token id
     * @param receiver vault share recipient
     * @param owner claim token holder
     */
    function redeem(
        uint256 tokenId,
        address receiver,
        address owner
    ) external;

    /**
     * @notice exchanges all claim tokens for vault shares
     */
    function redeemMax() external;

    /**
     * @notice exchanges all claim tokens for vault shares
     * @param receiver vault share recipient
     */
    function redeemMax(address receiver) external;

    /**
     * @notice exchanges all claim tokens for vault shares
     * @param receiver vault share recipient
     * @param owner claim token holder
     */
    function redeemMax(address receiver, address owner) external;

    /************************************************
     *  INITIALIZE EPOCH
     ***********************************************/

    /**
     * @notice transfers deposited collateral to vault, calculates the price per share
     */
    function processDeposits() external;

    /************************************************
     *  VIEW
     ***********************************************/

    /**
     * @notice returns the current claim token id
     * @return claim token id
     */
    function getCurrentTokenId() external view returns (uint256);

    /**
     * @notice returns the current epoch of the queue
     * @return epoch id
     */
    function getEpoch() external view returns (uint64);

    /**
     * @notice returns the max total value locked of the vault
     * @return max total value
     */
    function getMaxTVL() external view returns (uint256);

    /**
     * @notice returns the price per share for a given claim token id
     * @param tokenId claim token id
     * @return price per share
     */
    function getPricePerShare(uint256 tokenId) external view returns (uint256);

    /**
     * @notice returns unredeemed vault shares available for a given claim token
     * @param tokenId claim token id
     * @return unredeemed vault share amount
     */
    function previewUnredeemed(uint256 tokenId) external view returns (uint256);

    /**
     * @notice returns unredeemed vault shares available for a given claim token
     * @param tokenId claim token id
     * @param owner claim token holder
     * @return unredeemed vault share amount
     */
    function previewUnredeemed(uint256 tokenId, address owner)
        external
        view
        returns (uint256);

    /**
     * @notice returns unredeemed vault shares available for all claim tokens
     * @param owner claim token holder
     * @return unredeemed vault share amount
     */
    function previewMaxUnredeemed(address owner)
        external
        view
        returns (uint256);
}

File 38 of 46 : IERC1155Receiver.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IERC165 } from '../../introspection/IERC165.sol';

/**
 * @title ERC1155 transfer receiver interface
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @notice validate receipt of ERC1155 transfer
     * @param operator executor of transfer
     * @param from sender of tokens
     * @param id token ID received
     * @param value quantity of tokens received
     * @param data data payload
     * @return function's own selector if transfer is accepted
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @notice validate receipt of ERC1155 batch transfer
     * @param operator executor of transfer
     * @param from sender of tokens
     * @param ids token IDs received
     * @param values quantities of tokens received
     * @param data data payload
     * @return function's own selector if transfer is accepted
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

File 39 of 46 : IExchangeHelper.sol
// SPDX-License-Identifier: LGPL-3.0-or-later

pragma solidity ^0.8.0;

/**
 * @title Premia Exchange Helper
 * @dev deployed standalone and referenced by internal functions
 * @dev do NOT set approval to this contract!
 */
interface IExchangeHelper {
    struct SwapArgs {
        // token to pass in to swap
        address tokenIn;
        // amount of tokenIn to trade
        uint256 amountInMax;
        //min amount out to be used to purchase
        uint256 amountOutMin;
        // exchange address to call to execute the trade
        address callee;
        // address for which to set allowance for the trade
        address allowanceTarget;
        // data to execute the trade
        bytes data;
        // address to which refund excess tokens
        address refundAddress;
    }

    /**
     * @notice perform arbitrary swap transaction
     * @param sourceToken source token to pull into this address
     * @param targetToken target token to buy
     * @param pullAmount amount of source token to start the trade
     * @param callee exchange address to call to execute the trade.
     * @param allowanceTarget address for which to set allowance for the trade
     * @param data calldata to execute the trade
     * @param refundAddress address that un-used source token goes to
     * @return amountOut quantity of targetToken yielded by swap
     */
    function swapWithToken(
        address sourceToken,
        address targetToken,
        uint256 pullAmount,
        address callee,
        address allowanceTarget,
        bytes calldata data,
        address refundAddress
    ) external returns (uint256 amountOut);
}

File 40 of 46 : EnumerableSet.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title Set implementation with enumeration functions
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
 */
library EnumerableSet {
    struct Set {
        bytes32[] _values;
        // 1-indexed to allow 0 to signify nonexistence
        mapping(bytes32 => uint256) _indexes;
    }

    struct Bytes32Set {
        Set _inner;
    }

    struct AddressSet {
        Set _inner;
    }

    struct UintSet {
        Set _inner;
    }

    function at(Bytes32Set storage set, uint256 index)
        internal
        view
        returns (bytes32)
    {
        return _at(set._inner, index);
    }

    function at(AddressSet storage set, uint256 index)
        internal
        view
        returns (address)
    {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    function at(UintSet storage set, uint256 index)
        internal
        view
        returns (uint256)
    {
        return uint256(_at(set._inner, index));
    }

    function contains(Bytes32Set storage set, bytes32 value)
        internal
        view
        returns (bool)
    {
        return _contains(set._inner, value);
    }

    function contains(AddressSet storage set, address value)
        internal
        view
        returns (bool)
    {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    function contains(UintSet storage set, uint256 value)
        internal
        view
        returns (bool)
    {
        return _contains(set._inner, bytes32(value));
    }

    function indexOf(Bytes32Set storage set, bytes32 value)
        internal
        view
        returns (uint256)
    {
        return _indexOf(set._inner, value);
    }

    function indexOf(AddressSet storage set, address value)
        internal
        view
        returns (uint256)
    {
        return _indexOf(set._inner, bytes32(uint256(uint160(value))));
    }

    function indexOf(UintSet storage set, uint256 value)
        internal
        view
        returns (uint256)
    {
        return _indexOf(set._inner, bytes32(value));
    }

    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    function add(Bytes32Set storage set, bytes32 value)
        internal
        returns (bool)
    {
        return _add(set._inner, value);
    }

    function add(AddressSet storage set, address value)
        internal
        returns (bool)
    {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    function remove(Bytes32Set storage set, bytes32 value)
        internal
        returns (bool)
    {
        return _remove(set._inner, value);
    }

    function remove(AddressSet storage set, address value)
        internal
        returns (bool)
    {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    function remove(UintSet storage set, uint256 value)
        internal
        returns (bool)
    {
        return _remove(set._inner, bytes32(value));
    }

    function _at(Set storage set, uint256 index)
        private
        view
        returns (bytes32)
    {
        require(
            set._values.length > index,
            'EnumerableSet: index out of bounds'
        );
        return set._values[index];
    }

    function _contains(Set storage set, bytes32 value)
        private
        view
        returns (bool)
    {
        return set._indexes[value] != 0;
    }

    function _indexOf(Set storage set, bytes32 value)
        private
        view
        returns (uint256)
    {
        unchecked {
            return set._indexes[value] - 1;
        }
    }

    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    function _remove(Set storage set, bytes32 value) private returns (bool) {
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            unchecked {
                bytes32 last = set._values[set._values.length - 1];

                // move last value to now-vacant index

                set._values[valueIndex - 1] = last;
                set._indexes[last] = valueIndex;
            }
            // clear last index

            set._values.pop();
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }
}

File 41 of 46 : OrderBook.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title Knox Auction Order Book Library
 * @dev based on PiperMerriam's Grove v0.3
 * https://github.com/pipermerriam/ethereum-grove
 */

library OrderBook {
    struct Index {
        uint256 head;
        uint256 length;
        uint256 root;
        mapping(uint256 => Order) orders;
    }

    struct Order {
        Data data;
        uint256 parent;
        uint256 left;
        uint256 right;
        uint256 height;
    }

    struct Data {
        uint256 id;
        int128 price64x64;
        uint256 size;
        address buyer;
    }

    /// @dev Retrieve the highest bid in the order book.
    /// @param index The index that the order is part of.
    function _head(Index storage index) internal view returns (uint256) {
        return index.head;
    }

    /// @dev Retrieve the number of bids in the order book.
    /// @param index The index that the order is part of.
    function _length(Index storage index) internal view returns (uint256) {
        return index.length;
    }

    /// @dev Retrieve the id, price, size, and buyer for the order.
    /// @param index The index that the order is part of.
    /// @param id The id for the order to be looked up.
    function _getOrderById(Index storage index, uint256 id)
        internal
        view
        returns (Data memory)
    {
        return index.orders[id].data;
    }

    /// @dev Returns the previous bid in descending order.
    /// @param index The index that the order is part of.
    /// @param id The id for the order to be looked up.
    function _getPreviousOrder(Index storage index, uint256 id)
        internal
        view
        returns (uint256)
    {
        Order storage currentOrder = index.orders[id];

        if (currentOrder.data.id == 0) {
            // Unknown order, just return 0;
            return 0;
        }

        Order memory child;

        if (currentOrder.left != 0) {
            // Trace left to latest child in left tree.
            child = index.orders[currentOrder.left];

            while (child.right != 0) {
                child = index.orders[child.right];
            }
            return child.data.id;
        }

        if (currentOrder.parent != 0) {
            // Now we trace back up through parent relationships, looking
            // for a link where the child is the right child of it's
            // parent.
            Order storage parent = index.orders[currentOrder.parent];
            child = currentOrder;

            while (true) {
                if (parent.right == child.data.id) {
                    return parent.data.id;
                }

                if (parent.parent == 0) {
                    break;
                }
                child = parent;
                parent = index.orders[parent.parent];
            }
        }

        // This is the first order, and has no previous order.
        return 0;
    }

    /// @dev Returns the next bid in descending order.
    /// @param index The index that the order is part of.
    /// @param id The id for the order to be looked up.
    function _getNextOrder(Index storage index, uint256 id)
        internal
        view
        returns (uint256)
    {
        Order storage currentOrder = index.orders[id];

        if (currentOrder.data.id == 0) {
            // Unknown order, just return 0;
            return 0;
        }

        Order memory child;

        if (currentOrder.right != 0) {
            // Trace right to earliest child in right tree.
            child = index.orders[currentOrder.right];

            while (child.left != 0) {
                child = index.orders[child.left];
            }
            return child.data.id;
        }

        if (currentOrder.parent != 0) {
            // if the order is the left child of it's parent, then the
            // parent is the next one.
            Order storage parent = index.orders[currentOrder.parent];
            child = currentOrder;

            while (true) {
                if (parent.left == child.data.id) {
                    return parent.data.id;
                }

                if (parent.parent == 0) {
                    break;
                }
                child = parent;
                parent = index.orders[parent.parent];
            }

            // Now we need to trace all the way up checking to see if any parent is the
        }

        // This is the final order.
        return 0;
    }

    /// @dev Updates or Inserts the id into the index at its appropriate location based on the price provided.
    /// @param index The index that the order is part of.
    // / @param id The unique identifier of the data element the index order will represent.
    /// @param price64x64 The unit price specified by the buyer.
    /// @param size The size specified by the buyer.
    /// @param buyer The buyers wallet address.
    function _insert(
        Index storage index,
        int128 price64x64,
        uint256 size,
        address buyer
    ) internal returns (uint256) {
        index.length = index.length + 1;
        uint256 id = index.length;

        Data memory data = _getOrderById(index, index.head);

        int128 highestPricePaid = data.price64x64;

        if (index.head == 0 || price64x64 > highestPricePaid) {
            index.head = id;
        }

        if (index.orders[id].data.id == id) {
            // A order with this id already exists.  If the price is
            // the same, then just return early, otherwise, remove it
            // and reinsert it.
            if (index.orders[id].data.price64x64 == price64x64) {
                return id;
            }
            _remove(index, id);
        }

        uint256 previousOrderId = 0;

        if (index.root == 0) {
            index.root = id;
        }
        Order storage currentOrder = index.orders[index.root];

        // Do insertion
        while (true) {
            if (currentOrder.data.id == 0) {
                // This is a new unpopulated order.
                currentOrder.data.id = id;
                currentOrder.parent = previousOrderId;
                currentOrder.data.price64x64 = price64x64;
                currentOrder.data.size = size;
                currentOrder.data.buyer = buyer;
                break;
            }

            // Set the previous order id.
            previousOrderId = currentOrder.data.id;

            // The new order belongs in the right subtree
            if (price64x64 <= currentOrder.data.price64x64) {
                if (currentOrder.right == 0) {
                    currentOrder.right = id;
                }
                currentOrder = index.orders[currentOrder.right];
                continue;
            }

            // The new order belongs in the left subtree.
            if (currentOrder.left == 0) {
                currentOrder.left = id;
            }
            currentOrder = index.orders[currentOrder.left];
        }

        // Rebalance the tree
        _rebalanceTree(index, currentOrder.data.id);

        return id;
    }

    /// @dev Remove the order for the given unique identifier from the index.
    /// @param index The index that should be removed
    /// @param id The unique identifier of the data element to remove.
    function _remove(Index storage index, uint256 id) internal returns (bool) {
        if (id == index.head) {
            index.head = _getNextOrder(index, id);
        }

        Order storage replacementOrder;
        Order storage parent;
        Order storage child;
        uint256 rebalanceOrigin;

        Order storage orderToDelete = index.orders[id];

        if (orderToDelete.data.id != id) {
            // The id does not exist in the tree.
            return false;
        }

        if (orderToDelete.left != 0 || orderToDelete.right != 0) {
            // This order is not a leaf order and thus must replace itself in
            // it's tree by either the previous or next order.
            if (orderToDelete.left != 0) {
                // This order is guaranteed to not have a right child.
                replacementOrder = index.orders[
                    _getPreviousOrder(index, orderToDelete.data.id)
                ];
            } else {
                // This order is guaranteed to not have a left child.
                replacementOrder = index.orders[
                    _getNextOrder(index, orderToDelete.data.id)
                ];
            }
            // The replacementOrder is guaranteed to have a parent.
            parent = index.orders[replacementOrder.parent];

            // Keep note of the location that our tree rebalancing should
            // start at.
            rebalanceOrigin = replacementOrder.data.id;

            // Join the parent of the replacement order with any subtree of
            // the replacement order.  We can guarantee that the replacement
            // order has at most one subtree because of how getNextOrder and
            // getPreviousOrder are used.
            if (parent.left == replacementOrder.data.id) {
                parent.left = replacementOrder.right;
                if (replacementOrder.right != 0) {
                    child = index.orders[replacementOrder.right];
                    child.parent = parent.data.id;
                }
            }
            if (parent.right == replacementOrder.data.id) {
                parent.right = replacementOrder.left;
                if (replacementOrder.left != 0) {
                    child = index.orders[replacementOrder.left];
                    child.parent = parent.data.id;
                }
            }

            // Now we replace the orderToDelete with the replacementOrder.
            // This includes parent/child relationships for all of the
            // parent, the left child, and the right child.
            replacementOrder.parent = orderToDelete.parent;
            if (orderToDelete.parent != 0) {
                parent = index.orders[orderToDelete.parent];
                if (parent.left == orderToDelete.data.id) {
                    parent.left = replacementOrder.data.id;
                }
                if (parent.right == orderToDelete.data.id) {
                    parent.right = replacementOrder.data.id;
                }
            } else {
                // If the order we are deleting is the root order update the
                // index root order pointer.
                index.root = replacementOrder.data.id;
            }

            replacementOrder.left = orderToDelete.left;
            if (orderToDelete.left != 0) {
                child = index.orders[orderToDelete.left];
                child.parent = replacementOrder.data.id;
            }

            replacementOrder.right = orderToDelete.right;
            if (orderToDelete.right != 0) {
                child = index.orders[orderToDelete.right];
                child.parent = replacementOrder.data.id;
            }
        } else if (orderToDelete.parent != 0) {
            // The order being deleted is a leaf order so we only erase it's
            // parent linkage.
            parent = index.orders[orderToDelete.parent];

            if (parent.left == orderToDelete.data.id) {
                parent.left = 0;
            }
            if (parent.right == orderToDelete.data.id) {
                parent.right = 0;
            }

            // keep note of where the rebalancing should begin.
            rebalanceOrigin = parent.data.id;
        } else {
            // This is both a leaf order and the root order, so we need to
            // unset the root order pointer.
            index.root = 0;
        }

        // Now we zero out all of the fields on the orderToDelete.
        orderToDelete.data.id = 0;
        orderToDelete.data.price64x64 = 0;
        orderToDelete.data.size = 0;
        orderToDelete.data.buyer = 0x0000000000000000000000000000000000000000;
        orderToDelete.parent = 0;
        orderToDelete.left = 0;
        orderToDelete.right = 0;
        orderToDelete.height = 0;

        // Walk back up the tree rebalancing
        if (rebalanceOrigin != 0) {
            _rebalanceTree(index, rebalanceOrigin);
        }

        return true;
    }

    function _rebalanceTree(Index storage index, uint256 id) private {
        // Trace back up rebalancing the tree and updating heights as
        // needed..
        Order storage currentOrder = index.orders[id];

        while (true) {
            int256 balanceFactor =
                _getBalanceFactor(index, currentOrder.data.id);

            if (balanceFactor == 2) {
                // Right rotation (tree is heavy on the left)
                if (_getBalanceFactor(index, currentOrder.left) == -1) {
                    // The subtree is leaning right so it need to be
                    // rotated left before the current order is rotated
                    // right.
                    _rotateLeft(index, currentOrder.left);
                }
                _rotateRight(index, currentOrder.data.id);
            }

            if (balanceFactor == -2) {
                // Left rotation (tree is heavy on the right)
                if (_getBalanceFactor(index, currentOrder.right) == 1) {
                    // The subtree is leaning left so it need to be
                    // rotated right before the current order is rotated
                    // left.
                    _rotateRight(index, currentOrder.right);
                }
                _rotateLeft(index, currentOrder.data.id);
            }

            if ((-1 <= balanceFactor) && (balanceFactor <= 1)) {
                _updateOrderHeight(index, currentOrder.data.id);
            }

            if (currentOrder.parent == 0) {
                // Reached the root which may be new due to tree
                // rotation, so set it as the root and then break.
                break;
            }

            currentOrder = index.orders[currentOrder.parent];
        }
    }

    function _getBalanceFactor(Index storage index, uint256 id)
        private
        view
        returns (int256)
    {
        Order storage order = index.orders[id];
        return
            int256(index.orders[order.left].height) -
            int256(index.orders[order.right].height);
    }

    function _updateOrderHeight(Index storage index, uint256 id) private {
        Order storage order = index.orders[id];
        order.height =
            _max(
                index.orders[order.left].height,
                index.orders[order.right].height
            ) +
            1;
    }

    function _max(uint256 a, uint256 b) private pure returns (uint256) {
        if (a >= b) {
            return a;
        }
        return b;
    }

    function _rotateLeft(Index storage index, uint256 id) private {
        Order storage originalRoot = index.orders[id];

        if (originalRoot.right == 0) {
            // Cannot rotate left if there is no right originalRoot to rotate into
            // place.
            revert();
        }

        // The right child is the new root, so it gets the original
        // `originalRoot.parent` as it's parent.
        Order storage newRoot = index.orders[originalRoot.right];
        newRoot.parent = originalRoot.parent;

        // The original root needs to have it's right child nulled out.
        originalRoot.right = 0;

        if (originalRoot.parent != 0) {
            // If there is a parent order, it needs to now point downward at
            // the newRoot which is rotating into the place where `order` was.
            Order storage parent = index.orders[originalRoot.parent];

            // figure out if we're a left or right child and have the
            // parent point to the new order.
            if (parent.left == originalRoot.data.id) {
                parent.left = newRoot.data.id;
            }
            if (parent.right == originalRoot.data.id) {
                parent.right = newRoot.data.id;
            }
        }

        if (newRoot.left != 0) {
            // If the new root had a left child, that moves to be the
            // new right child of the original root order
            Order storage leftChild = index.orders[newRoot.left];
            originalRoot.right = leftChild.data.id;
            leftChild.parent = originalRoot.data.id;
        }

        // Update the newRoot's left order to point at the original order.
        originalRoot.parent = newRoot.data.id;
        newRoot.left = originalRoot.data.id;

        if (newRoot.parent == 0) {
            index.root = newRoot.data.id;
        }

        _updateOrderHeight(index, originalRoot.data.id);
        _updateOrderHeight(index, newRoot.data.id);
    }

    function _rotateRight(Index storage index, uint256 id) private {
        Order storage originalRoot = index.orders[id];

        if (originalRoot.left == 0) {
            // Cannot rotate right if there is no left order to rotate into
            // place.
            revert();
        }

        // The left child is taking the place of order, so we update it's
        // parent to be the original parent of the order.
        Order storage newRoot = index.orders[originalRoot.left];
        newRoot.parent = originalRoot.parent;

        // Null out the originalRoot.left
        originalRoot.left = 0;

        if (originalRoot.parent != 0) {
            // If the order has a parent, update the correct child to point
            // at the newRoot now.
            Order storage parent = index.orders[originalRoot.parent];

            if (parent.left == originalRoot.data.id) {
                parent.left = newRoot.data.id;
            }
            if (parent.right == originalRoot.data.id) {
                parent.right = newRoot.data.id;
            }
        }

        if (newRoot.right != 0) {
            Order storage rightChild = index.orders[newRoot.right];
            originalRoot.left = newRoot.right;
            rightChild.parent = originalRoot.data.id;
        }

        // Update the new root's right order to point to the original order.
        originalRoot.parent = newRoot.data.id;
        newRoot.right = originalRoot.data.id;

        if (newRoot.parent == 0) {
            index.root = newRoot.data.id;
        }

        // Recompute heights.
        _updateOrderHeight(index, originalRoot.data.id);
        _updateOrderHeight(index, newRoot.data.id);
    }
}

File 42 of 46 : AggregatorV3Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface AggregatorV3Interface {
  function decimals() external view returns (uint8);

  function description() external view returns (string memory);

  function version() external view returns (uint256);

  // getRoundData and latestRoundData should both raise "No data present"
  // if they do not have data to report, instead of returning unset values
  // which could be misinterpreted as actual reported values.
  function getRoundData(uint80 _roundId)
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );

  function latestRoundData()
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );
}

File 43 of 46 : IERC1155Enumerable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IERC1155Internal } from '../IERC1155Internal.sol';

/**
 * @title ERC1155 enumerable and aggregate function interface
 */
interface IERC1155Enumerable is IERC1155Internal {
    /**
     * @notice query total minted supply of given token
     * @param id token id to query
     * @return token supply
     */
    function totalSupply(uint256 id) external view returns (uint256);

    /**
     * @notice query total number of holders for given token
     * @param id token id to query
     * @return quantity of holders
     */
    function totalHolders(uint256 id) external view returns (uint256);

    /**
     * @notice query holders of given token
     * @param id token id to query
     * @return list of holder addresses
     */
    function accountsByToken(uint256 id)
        external
        view
        returns (address[] memory);

    /**
     * @notice query tokens held by given address
     * @param account address to query
     * @return list of token ids
     */
    function tokensByAccount(address account)
        external
        view
        returns (uint256[] memory);
}

File 44 of 46 : IQueueEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title Knox Queue Events Interface
 */

interface IQueueEvents {
    /**
     * @notice emitted when a deposit is cancelled
     * @param epoch epoch id
     * @param depositer address of depositer
     * @param amount quantity of collateral assets removed from queue
     */
    event Cancel(uint64 indexed epoch, address depositer, uint256 amount);

    /**
     * @notice emitted when a deposit is made
     * @param epoch epoch id
     * @param depositer address of depositer
     * @param amount quantity of collateral assets added to queue
     */
    event Deposit(uint64 indexed epoch, address depositer, uint256 amount);

    /**
     * @notice emitted when the exchange helper contract address is updated
     * @param oldExchangeHelper previous exchange helper address
     * @param newExchangeHelper new exchange helper address
     * @param caller address of admin
     */
    event ExchangeHelperSet(
        address oldExchangeHelper,
        address newExchangeHelper,
        address caller
    );

    /**
     * @notice emitted when the max TVL is updated
     * @param epoch epoch id
     * @param oldMaxTVL previous max TVL amount
     * @param newMaxTVL new max TVL amount
     * @param caller address of admin
     */
    event MaxTVLSet(
        uint64 indexed epoch,
        uint256 oldMaxTVL,
        uint256 newMaxTVL,
        address caller
    );

    /**
     * @notice emitted when vault shares are redeemed
     * @param epoch epoch id
     * @param receiver address of receiver
     * @param depositer address of depositer
     * @param shares quantity of vault shares sent to receiver
     */
    event Redeem(
        uint64 indexed epoch,
        address receiver,
        address depositer,
        uint256 shares
    );

    /**
     * @notice emitted when the queued deposits are processed
     * @param epoch epoch id
     * @param deposits quantity of collateral assets processed
     * @param pricePerShare vault price per share calculated
     * @param shares quantity of vault shares sent to queue contract
     * @param claimTokenSupply quantity of claim tokens in supply
     */
    event ProcessQueuedDeposits(
        uint64 indexed epoch,
        uint256 deposits,
        uint256 pricePerShare,
        uint256 shares,
        uint256 claimTokenSupply
    );
}

File 45 of 46 : IERC4626.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IERC20 } from '../ERC20/IERC20.sol';
import { IERC4626Internal } from './IERC4626Internal.sol';

/**
 * @title ERC4626 interface
 * @dev see https://github.com/ethereum/EIPs/issues/4626
 */
interface IERC4626 is IERC4626Internal, IERC20 {
    /**
     * @notice get the address of the base token used for vault accountin purposes
     * @return base token address
     */
    function asset() external view returns (address);

    /**
     * @notice get the total quantity of the base asset currently managed by the vault
     * @return total managed asset amount
     */
    function totalAssets() external view returns (uint256);

    /**
     * @notice calculate the quantity of shares received in exchange for a given quantity of assets, not accounting for slippage
     * @param assetAmount quantity of assets to convert
     * @return shareAmount quantity of shares calculated
     */
    function convertToShares(uint256 assetAmount)
        external
        view
        returns (uint256 shareAmount);

    /**
     * @notice calculate the quantity of assets received in exchange for a given quantity of shares, not accounting for slippage
     * @param shareAmount quantity of shares to convert
     * @return assetAmount quantity of assets calculated
     */
    function convertToAssets(uint256 shareAmount)
        external
        view
        returns (uint256 assetAmount);

    /**
     * @notice calculate the maximum quantity of base assets which may be deposited on behalf of given receiver
     * @param receiver recipient of shares resulting from deposit
     * @return maxAssets maximum asset deposit amount
     */
    function maxDeposit(address receiver)
        external
        view
        returns (uint256 maxAssets);

    /**
     * @notice calculate the maximum quantity of shares which may be minted on behalf of given receiver
     * @param receiver recipient of shares resulting from deposit
     * @return maxShares maximum share mint amount
     */
    function maxMint(address receiver)
        external
        view
        returns (uint256 maxShares);

    /**
     * @notice calculate the maximum quantity of base assets which may be withdrawn by given holder
     * @param owner holder of shares to be redeemed
     * @return maxAssets maximum asset mint amount
     */
    function maxWithdraw(address owner)
        external
        view
        returns (uint256 maxAssets);

    /**
     * @notice calculate the maximum quantity of shares which may be redeemed by given holder
     * @param owner holder of shares to be redeemed
     * @return maxShares maximum share redeem amount
     */
    function maxRedeem(address owner) external view returns (uint256 maxShares);

    /**
     * @notice simulate a deposit of given quantity of assets
     * @param assetAmount quantity of assets to deposit
     * @return shareAmount quantity of shares to mint
     */
    function previewDeposit(uint256 assetAmount)
        external
        view
        returns (uint256 shareAmount);

    /**
     * @notice simulate a minting of given quantity of shares
     * @param shareAmount quantity of shares to mint
     * @return assetAmount quantity of assets to deposit
     */
    function previewMint(uint256 shareAmount)
        external
        view
        returns (uint256 assetAmount);

    /**
     * @notice simulate a withdrawal of given quantity of assets
     * @param assetAmount quantity of assets to withdraw
     * @return shareAmount quantity of shares to redeem
     */
    function previewWithdraw(uint256 assetAmount)
        external
        view
        returns (uint256 shareAmount);

    /**
     * @notice simulate a redemption of given quantity of shares
     * @param shareAmount quantity of shares to redeem
     * @return assetAmount quantity of assets to withdraw
     */
    function previewRedeem(uint256 shareAmount)
        external
        view
        returns (uint256 assetAmount);

    /**
     * @notice execute a deposit of assets on behalf of given address
     * @param assetAmount quantity of assets to deposit
     * @param receiver recipient of shares resulting from deposit
     * @return shareAmount quantity of shares to mint
     */
    function deposit(uint256 assetAmount, address receiver)
        external
        returns (uint256 shareAmount);

    /**
     * @notice execute a minting of shares on behalf of given address
     * @param shareAmount quantity of shares to mint
     * @param receiver recipient of shares resulting from deposit
     * @return assetAmount quantity of assets to deposit
     */
    function mint(uint256 shareAmount, address receiver)
        external
        returns (uint256 assetAmount);

    /**
     * @notice execute a withdrawal of assets on behalf of given address
     * @param assetAmount quantity of assets to withdraw
     * @param receiver recipient of assets resulting from withdrawal
     * @param owner holder of shares to be redeemed
     * @return shareAmount quantity of shares to redeem
     */
    function withdraw(
        uint256 assetAmount,
        address receiver,
        address owner
    ) external returns (uint256 shareAmount);

    /**
     * @notice execute a redemption of shares on behalf of given address
     * @param shareAmount quantity of shares to redeem
     * @param receiver recipient of assets resulting from withdrawal
     * @param owner holder of shares to be redeemed
     * @return assetAmount quantity of assets to withdraw
     */
    function redeem(
        uint256 shareAmount,
        address receiver,
        address owner
    ) external returns (uint256 assetAmount);
}

File 46 of 46 : IERC4626Internal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title Partial ERC4626 interface needed by internal functions
 */
interface IERC4626Internal {
    event Deposit(
        address indexed caller,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    event Withdraw(
        address indexed caller,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );
}

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

Contract ABI

[{"inputs":[{"internalType":"bool","name":"isCall","type":"bool"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"},{"indexed":false,"internalType":"int128","name":"strike64x64","type":"int128"},{"indexed":false,"internalType":"int128","name":"offsetStrike64x64","type":"int128"},{"indexed":false,"internalType":"int128","name":"spot64x64","type":"int128"},{"indexed":false,"internalType":"int128","name":"maxPrice64x64","type":"int128"},{"indexed":false,"internalType":"int128","name":"minPrice64x64","type":"int128"}],"name":"AuctionPricesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"},{"indexed":false,"internalType":"enum AuctionStorage.Status","name":"status","type":"uint8"}],"name":"AuctionStatusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int128","name":"oldDeltaOffset","type":"int128"},{"indexed":false,"internalType":"int128","name":"newDeltaOffset","type":"int128"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"DeltaOffsetSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldExchangeHelper","type":"address"},{"indexed":false,"internalType":"address","name":"newExchangeHelper","type":"address"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"ExchangeHelperSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"message","type":"string"}],"name":"Log","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMinSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMinSize","type":"uint256"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"MinSizeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"},{"indexed":false,"internalType":"uint128","name":"orderId","type":"uint128"},{"indexed":false,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"int128","name":"price64x64","type":"int128"},{"indexed":false,"internalType":"uint256","name":"size","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isLimitOrder","type":"bool"}],"name":"OrderAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"},{"indexed":false,"internalType":"uint128","name":"orderId","type":"uint128"},{"indexed":false,"internalType":"address","name":"buyer","type":"address"}],"name":"OrderCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"},{"indexed":false,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"refund","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fill","type":"uint256"}],"name":"OrderWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPricer","type":"address"},{"indexed":false,"internalType":"address","name":"newPricer","type":"address"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"PricerSet","type":"event"},{"inputs":[],"name":"ERC20","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"Pool","outputs":[{"internalType":"contract IPremiaPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"Vault","outputs":[{"internalType":"contract IVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"int128","name":"price64x64","type":"int128"},{"internalType":"uint256","name":"size","type":"uint256"}],"name":"addLimitOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"uint256","name":"maxCost","type":"uint256"}],"name":"addMarketOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"uint128","name":"orderId","type":"uint128"}],"name":"cancelLimitOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"clearingPrice64x64","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"finalizeAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"getAuction","outputs":[{"components":[{"internalType":"enum AuctionStorage.Status","name":"status","type":"uint8"},{"internalType":"uint64","name":"expiry","type":"uint64"},{"internalType":"int128","name":"strike64x64","type":"int128"},{"internalType":"int128","name":"maxPrice64x64","type":"int128"},{"internalType":"int128","name":"minPrice64x64","type":"int128"},{"internalType":"int128","name":"lastPrice64x64","type":"int128"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"processedTime","type":"uint256"},{"internalType":"uint256","name":"totalContracts","type":"uint256"},{"internalType":"uint256","name":"totalContractsSold","type":"uint256"},{"internalType":"uint256","name":"totalUnclaimedContracts","type":"uint256"},{"internalType":"uint256","name":"totalPremiums","type":"uint256"},{"internalType":"uint256","name":"longTokenId","type":"uint256"}],"internalType":"struct AuctionStorage.Auction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDeltaOffset64x64","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMinSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"uint128","name":"orderId","type":"uint128"}],"name":"getOrderById","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"int128","name":"price64x64","type":"int128"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"address","name":"buyer","type":"address"}],"internalType":"struct OrderBook.Data","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"getStatus","outputs":[{"internalType":"enum AuctionStorage.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"getTotalContracts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"getTotalContractsSold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"buyer","type":"address"}],"name":"getUniqueOrderIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"uint64","name":"expiry","type":"uint64"},{"internalType":"int128","name":"strike64x64","type":"int128"},{"internalType":"uint256","name":"longTokenId","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"internalType":"struct AuctionStorage.InitAuction","name":"initAuction","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"lastPrice64x64","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"address","name":"buyer","type":"address"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"priceCurve64x64","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"processAuction","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"setAuctionPrices","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int128","name":"newDeltaOffset64x64","type":"int128"}],"name":"setDeltaOffset64x64","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newExchangeHelper","type":"address"}],"name":"setExchangeHelper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMinSize","type":"uint256"}],"name":"setMinSize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPricer","type":"address"}],"name":"setPricer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address","name":"callee","type":"address"},{"internalType":"address","name":"allowanceTarget","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"address","name":"refundAddress","type":"address"}],"internalType":"struct IExchangeHelper.SwapArgs","name":"s","type":"tuple"},{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"int128","name":"price64x64","type":"int128"},{"internalType":"uint256","name":"size","type":"uint256"}],"name":"swapAndAddLimitOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address","name":"callee","type":"address"},{"internalType":"address","name":"allowanceTarget","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"address","name":"refundAddress","type":"address"}],"internalType":"struct IExchangeHelper.SwapArgs","name":"s","type":"tuple"},{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"uint256","name":"maxCost","type":"uint256"}],"name":"swapAndAddMarketOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6101606040523480156200001257600080fd5b5060405162005ff438038062005ff48339810160408190526200003591620001fb565b83151560809081526001600160a01b0384166101008190526040805163e4a0ce2f60e01b81529051879387938793879360009363e4a0ce2f92600480820193918290030181865afa1580156200008f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000b591906200025e565b90506000608051620000cc578160200151620000cf565b81515b905081602001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000114573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200013a9190620002f2565b60ff1660a08160ff168152505081600001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200018a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b09190620002f2565b60ff1660c0526001600160a01b0390811660e05292831661012052501661014052506200031e945050505050565b80516001600160a01b0381168114620001f657600080fd5b919050565b600080600080608085870312156200021257600080fd5b845180151581146200022357600080fd5b93506200023360208601620001de565b92506200024360408601620001de565b91506200025360608601620001de565b905092959194509250565b6000608082840312156200027157600080fd5b604051608081016001600160401b0381118282101715620002a257634e487b7160e01b600052604160045260246000fd5b604052620002b083620001de565b8152620002c060208401620001de565b6020820152620002d360408401620001de565b6040820152620002e660608401620001de565b60608201529392505050565b6000602082840312156200030557600080fd5b815160ff811681146200031757600080fd5b9392505050565b60805160a05160c05160e051610100516101205161014051615bbe620004366000396000818161052201528181611fc901528181612102015281816127bb0152818161283201526128b001526000818161037901528181611271015281816115b8015281816116e8015281816147c0015261484601526000818161025001528181612b3d0152613c240152600081816106550152818161086201528181610f5c015281816111b0015281816116c501528181611be101528181611ff301528181612a520152612bb501526000613d4b015260008181613d6c01526149000152600081816122f20152818161236401528181612431015281816124ce01528181613c9d01528181613cfa01526148de0152615bbe6000f3fe6080604052600436106102045760003560e01c8063a16594b911610118578063cc4aa204116100a0578063d3f44d841161006f578063d3f44d84146106bf578063d999ec8f146106df578063da60d637146106ff578063df4c96701461071f578063f23a6e611461074c57600080fd5b8063cc4aa20414610643578063d07041e014610677578063d2639b621461068c578063d26fef61146106ac57600080fd5b8063b670b058116100e7578063b670b05814610564578063ba728b5f14610584578063ba98d741146105a4578063bc12e3d7146105d1578063bc197c81146105fe57600080fd5b8063a16594b9146104c3578063ac9650d8146104e3578063ad5c464814610510578063b044ab751461054457600080fd5b80632d2c44f21161019b57806379e1aa381161016a57806379e1aa38146103e35780637a4f8d3a146103f65780637e28e8bf146104245780637f32cf41146104445780638df5db82146104a357600080fd5b80632d2c44f21461036757806357530e871461039b578063579e792f146103b0578063750f0acc146103c357600080fd5b806321651f8e116101d757806321651f8e146102bf57806327f39951146102f257806329390370146103275780632a0d3a291461034757600080fd5b806301ffc9a71461020957806307f3b8bb1461023e5780630cfd168f1461028a57806318f4a50a1461029f575b600080fd5b34801561021557600080fd5b50610229610224366004614ef2565b610778565b60405190151581526020015b60405180910390f35b34801561024a57600080fd5b506102727f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610235565b61029d610298366004614f38565b6107bb565b005b3480156102ab57600080fd5b5061029d6102ba366004614f6b565b6108a8565b3480156102cb57600080fd5b506102df6102da366004614f6b565b610be6565b604051600f9190910b8152602001610235565b3480156102fe57600080fd5b5061031261030d366004614f6b565b610c1f565b60408051928352602083019190915201610235565b34801561033357600080fd5b5061029d610342366004614f9d565b610c35565b34801561035357600080fd5b5061029d610362366004614fc7565b610d8f565b34801561037357600080fd5b506102727f000000000000000000000000000000000000000000000000000000000000000081565b3480156103a757600080fd5b506102df610ec0565b61029d6103be366004614ff6565b610ecf565b3480156103cf57600080fd5b5061029d6103de366004614f6b565b610fab565b61029d6103f136600461505d565b61111f565b34801561040257600080fd5b50610416610411366004614f6b565b611200565b604051908152602001610235565b34801561043057600080fd5b506102df61043f366004614f6b565b61120b565b34801561045057600080fd5b5061046461045f3660046150b9565b611241565b604051610235919081518152602080830151600f0b90820152604080830151908201526060918201516001600160a01b03169181019190915260800190565b3480156104af57600080fd5b5061029d6104be36600461513e565b61125a565b3480156104cf57600080fd5b506102df6104de366004614f6b565b611462565b3480156104ef57600080fd5b506105036104fe3660046151ce565b611493565b604051610235919061529a565b34801561051c57600080fd5b506102727f000000000000000000000000000000000000000000000000000000000000000081565b34801561055057600080fd5b5061031261055f366004614f6b565b61159e565b34801561057057600080fd5b5061029d61057f3660046152fc565b611735565b34801561059057600080fd5b5061029d61059f366004614f6b565b611809565b3480156105b057600080fd5b506105c46105bf366004614f6b565b6118cd565b604051610235919061534d565b3480156105dd57600080fd5b506105f16105ec366004614f6b565b6118d8565b604051610235919061535b565b34801561060a57600080fd5b5061062a61061936600461552e565b63bc197c8160e01b95945050505050565b6040516001600160e01b03199091168152602001610235565b34801561064f57600080fd5b506102727f000000000000000000000000000000000000000000000000000000000000000081565b34801561068357600080fd5b506104166118e9565b34801561069857600080fd5b506104166106a7366004614f6b565b6118f3565b61029d6106ba3660046155d7565b61194b565b3480156106cb57600080fd5b5061029d6106da3660046150b9565b6119f8565b3480156106eb57600080fd5b5061029d6106fa366004614f9d565b611c62565b34801561070b57600080fd5b5061031261071a366004615616565b611dbc565b34801561072b57600080fd5b5061073f61073a366004614f9d565b611dd5565b6040516102359190615649565b34801561075857600080fd5b5061062a61076736600461568d565b63f23a6e6160e01b95945050505050565b6001600160e01b0319811660009081527f326d0c59a7612f6a9919e2a8ee333c80ba689d8ba2634de89c85cbb04832e705602052604081205460ff165b92915050565b600080516020615b698339815191528054600214156107f55760405162461bcd60e51b81526004016107ec906156f1565b60405180910390fd5b600281556000610803611e9b565b6001600160401b0386166000908152600282016020526040902090915061082981611ebf565b60008061083884848989611f09565b91509150600061084782611fbe565b905061088a3330610858848661573e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692919061217a565b61089985858b868c60006121e5565b50506001909355505050505050565b60006108b2611e9b565b6001600160401b0383166000908152600282016020526040902080549192509060ff1660048111156108e6576108e6615315565b6001146109055760405162461bcd60e51b81526004016107ec90615755565b6107088160030154610917919061573e565b421161095b5760405162461bcd60e51b815260206004820152601360248201527270726963652073657420746f6f206561726c7960681b60448201526064016107ec565b60018101546000600160801b909104600f0b131580610985575060018101546000600f9190910b13155b6109ca5760405162461bcd60e51b81526020600482015260166024820152751c1c9a58d95cc8185c9948185b1c9958591e481cd95d60521b60448201526064016107ec565b4281600301541115610bd7576000808360060160009054906101000a90046001600160a01b03166001600160a01b031663d33b48b56040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610a4a575060408051601f3d908101601f19168201909252610a4791810190615784565b60015b610ac357610a566157a1565b806308c379a01415610ab75750610a6b6157bd565b80610a765750610ab9565b7fcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab81604051610aa59190615846565b60405180910390a16000925050610ac6565b505b3d6000803e3d6000fd5b91505b60068401548354604051631d94c9b360e01b81526101009091046001600160401b031660048201526001600160a01b0390911690631d94c9b390602401602060405180830381865afa925050508015610b3c575060408051601f3d908101601f19168201909252610b3991810190615784565b60015b610ba957610b486157a1565b806308c379a01415610ab75750610b5d6157bd565b80610b685750610ab9565b7fcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab81604051610b979190615846565b60405180910390a16000915050610bac565b90505b600082600f0b138015610bc25750600081600f0b135b15610bd457610bd484848785856122cb565b50505b610be181846125ca565b505050565b600080610bf1611e9b565b6001600160401b03841660009081526002820160205260409020909150610c1781612624565b949350505050565b600080610c2c833361269a565b91509150915091565b600080516020615b49833981519152546001600160a01b03163314610c6c5760405162461bcd60e51b81526004016107ec90615859565b6000610c76611e9b565b90506001600160a01b038216610cc55760405162461bcd60e51b81526020600482015260146024820152731859191c995cdcc81b9bdd081c1c9bdd9a59195960621b60448201526064016107ec565b60068101546001600160a01b0383811691161415610d1e5760405162461bcd60e51b81526020600482015260166024820152751b995dc81859191c995cdcc8195c5d585b1cc81bdb1960521b60448201526064016107ec565b6006810154604080516001600160a01b03928316815291841660208301523382820152517faa40df73b7e66d2e4e3a90deb47486303ca82739a96c5595ba8c68d00482fed29181900360600190a160060180546001600160a01b0319166001600160a01b0392909216919091179055565b600080516020615b49833981519152546001600160a01b03163314610dc65760405162461bcd60e51b81526004016107ec90615859565b6000610dd0611e9b565b9050600082600f0b13610e125760405162461bcd60e51b815260206004820152600a602482015269064656c7461203c3d20360b41b60448201526064016107ec565b68010000000000000000600f83900b12610e5a5760405162461bcd60e51b815260206004820152600960248201526864656c7461203e203160b81b60448201526064016107ec565b805460408051600f92830b81529184900b60208301523382820152517f8ade3304a9dbce06100c268f7f1f6e66c1627bf10e8a495977290d0625148eb99181900360600190a180546001600160801b0319166001600160801b0392909216919091179055565b6000610eca6126c2565b905090565b600080516020615b69833981519152805460021415610f005760405162461bcd60e51b81526004016107ec906156f1565b600281556000610f0e611e9b565b6001600160401b03861660009081526002820160205260409020909150610f34816126d5565b6000610f4183878761270a565b6005840154909150600090610f80906001600160a01b03168a7f00000000000000000000000000000000000000000000000000000000000000006127a9565b9050610f8d818333612a32565b610f9c84848a8a8a60016121e5565b50506001909255505050505050565b600080516020615b69833981519152805460021415610fdc5760405162461bcd60e51b81526004016107ec906156f1565b600281556000610fea611e9b565b6001600160401b0384166000908152600282016020526040902080549192509060ff16600481111561101e5761101e615315565b600314806110415750805460ff16600481111561103d5761103d615315565b6004145b61108d5760405162461bcd60e51b815260206004820181905260248201527f73746174757320213d2070726f636573736564207c7c2063616e63656c6c656460448201526064016107ec565b805460ff1660048111156110a3576110a3615315565b6003141561110c5760058101546110bd9062015180615890565b42101561110c5760405162461bcd60e51b815260206004820152601960248201527f686f6c6420706572696f6420686173206e6f7420656e6465640000000000000060448201526064016107ec565b6111168285612a90565b50506001905550565b600080516020615b698339815191528054600214156111505760405162461bcd60e51b81526004016107ec906156f1565b60028155600061115e611e9b565b6001600160401b0386166000908152600282016020526040902090915061118481611ebf565b60008061119384848989611f09565b600586015491935091506000906111d4906001600160a01b03168b7f00000000000000000000000000000000000000000000000000000000000000006127a9565b90506111e1818333612a32565b6111f085858b868c60006121e5565b5050600190935550505050505050565b60006107b582612c30565b600080611216611e9b565b6001600160401b03841660009081526002820160205260409020909150610c178160020154600f0b90565b611249614e04565b6112538383612c5f565b9392505050565b6000611264611e9b565b9050336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146112c75760405162461bcd60e51b8152602060048201526006602482015265085d985d5b1d60d21b60448201526064016107ec565b60006112d1611e9b565b83516001600160401b031660009081526002820160205260408120919250815460ff16600481111561130557611305615315565b146113525760405162461bcd60e51b815260206004820152601760248201527f73746174757320213d20756e696e697469616c697a656400000000000000000060448201526064016107ec565b8360a00151846080015110158061136c5750836080015142115b80611383575083602001516001600160401b031642115b80611396575060008460400151600f0b13155b806113a357506060840151155b156113d45783516001600160401b03166000908152600283016020526040902084516113cf9190612ca2565b61145c565b6020840151815460408601516001600160801b0316600160481b0278ffffffffffffffffffffffffffffffff000000000000000000196001600160401b039093166101000292909216610100600160c81b0319909116171781556080840151600382015560a084015160048201556060840151600a820155835161145c908290600190612cb1565b50505050565b60008061146d611e9b565b6001600160401b03841660009081526002820160205260409020909150610c1781612d20565b6060816001600160401b038111156114ad576114ad6150fc565b6040519080825280602002602001820160405280156114e057816020015b60608152602001906001900390816114cb5790505b50905060005b828110156115975760008030868685818110611504576115046158a8565b905060200281019061151691906158be565b604051611524929190615904565b600060405180830381855af49150503d806000811461155f576040519150601f19603f3d011682016040523d82523d6000602084013e611564565b606091505b50915091508115610ab95780848481518110611582576115826158a8565b602002602001018190525050506001016114e6565b5092915050565b60008060006115ab611e9b565b9050336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461160e5760405162461bcd60e51b8152602060048201526006602482015265085d985d5b1d60d21b60448201526064016107ec565b6000611618611e9b565b6001600160401b0386166000908152600282016020526040902080549192509060ff16600481111561164c5761164c615315565b6002146116915760405162461bcd60e51b81526020600482015260136024820152721cdd185d1d5cc8084f48199a5b985b1a5e9959606a1b60448201526064016107ec565b6116b081600701546116a78360020154600f0b90565b600f0b90612dd2565b6009820181905561170d906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016907f000000000000000000000000000000000000000000000000000000000000000090612e3a565b42600582015561171f81600388612cb1565b8060090154816007015494509450505050915091565b600080516020615b49833981519152546001600160a01b0316331461176c5760405162461bcd60e51b81526004016107ec90615859565b6000611776611e9b565b9050600082116117c05760405162461bcd60e51b815260206004820152601560248201527476616c75652065786365656473206d696e696d756d60581b60448201526064016107ec565b600181015460408051918252602082018490523382820152517f1f1913f02d98f08a2ed8c776d0559838fe3804f17663b57486c274065646ceb99181900360600190a160010155565b6000611813611e9b565b6001600160401b038316600090815260028201602052604090206004810154919250906118439062015180615890565b4211801561188557506001815460ff16600481111561186457611864615315565b148061188557506002815460ff16600481111561188357611883615315565b145b1561189457610be18184612ca2565b806003015442101580156118bd57506001815460ff1660048111156118bb576118bb615315565b145b15610be157610be1828285612e6a565b60006107b582612edc565b6118e0614e38565b6107b582612f0b565b6000610eca613019565b6000806118fe611e9b565b6001600160401b0384166000908152600282016020526040902060038101549192509015801590611933575080600301544210155b1561194157610c178461302c565b5060009392505050565b600080516020615b6983398151915280546002141561197c5760405162461bcd60e51b81526004016107ec906156f1565b60028155600061198a611e9b565b6001600160401b038616600090815260028201602052604090209091506119b0816126d5565b60006119bd83878761270a565b905060006119ca82611fbe565b90506119db3330610858848661573e565b6119ea84848a8a8a60016121e5565b505060019092555050505050565b600080516020615b69833981519152805460021415611a295760405162461bcd60e51b81526004016107ec906156f1565b600281556000611a37611e9b565b6001600160401b03851660009081526002820160205260409020909150611a5d816126d5565b6000846001600160801b031611611aa95760405162461bcd60e51b815260206004820152601060248201526f1a5b9d985b1a59081bdc99195c881a5960821b60448201526064016107ec565b6001600160401b0385166000908152600383016020526040812090611ad7826001600160801b03881661305b565b60608101519091506001600160a01b0316611b2b5760405162461bcd60e51b81526020600482015260146024820152731bdc99195c88191bd95cc81b9bdd08195e1a5cdd60621b60448201526064016107ec565b60608101516001600160a01b03163314611b7d5760405162461bcd60e51b8152602060048201526013602482015272313abcb2b910109e9036b9b39739b2b73232b960691b60448201526064016107ec565b611b90826001600160801b0388166130b4565b50611b9c848888613391565b82600301544210611bb257611bb2848489612e6a565b6000611bd282604001518360200151600f0b612dd290919063ffffffff16565b9050611c086001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163383612e3a565b604080516001600160801b03891681523360208201526001600160401b038a16917fb7a419a9cad0cf4a1610023a7ee67f873ba51a63189b14b543ee6f31db8b7f3c910160405180910390a2505060019093555050505050565b600080516020615b49833981519152546001600160a01b03163314611c995760405162461bcd60e51b81526004016107ec90615859565b6000611ca3611e9b565b90506001600160a01b038216611cf25760405162461bcd60e51b81526020600482015260146024820152731859191c995cdcc81b9bdd081c1c9bdd9a59195960621b60448201526064016107ec565b60058101546001600160a01b0383811691161415611d4b5760405162461bcd60e51b81526020600482015260166024820152751b995dc81859191c995cdcc8195c5d585b1cc81bdb1960521b60448201526064016107ec565b6005810154604080516001600160a01b03928316815291841660208301523382820152517f045d485de10addb86db6ce795700266572ef7d9132df09a384062b5e82a093739181900360600190a160050180546001600160a01b0319166001600160a01b0392909216919091179055565b600080611dc9848461269a565b915091505b9250929050565b60606000611de1611e9b565b6001600160a01b03841660009081526004820160205260408120919250611e078261344e565b6001600160401b03811115611e1e57611e1e6150fc565b604051908082528060200260200182016040528015611e47578160200160208202803683370190505b50905060005b611e568361344e565b811015611e92576000611e698483613458565b905080838381518110611e7e57611e7e6158a8565b602090810291909101015250600101611e4d565b50949350505050565b7f7f75137652cf01fd4e0a016c479a4a2bdc1018772b7fc0eab68410c366c40cbb90565b805460ff166004811115611ed557611ed5615315565b600114611ef45760405162461bcd60e51b81526004016107ec90615755565b611efd81613464565b611f06816134fa565b50565b6000808560010154841015611f515760405162461bcd60e51b815260206004820152600e60248201526d73697a65203c206d696e696d756d60901b60448201526064016107ec565b6000611f5c86612d20565b90506000611f6e600f83900b87612dd2565b905080851015611fb15760405162461bcd60e51b815260206004820152600e60248201526d18dbdcdd080f881b585e10dbdcdd60921b60448201526064016107ec565b9097909650945050505050565b60008034156107b5577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461205d5760405162461bcd60e51b81526020600482015260126024820152710c6ded8d8c2e8cae4c2d840427a40ee8aa8960731b60448201526064016107ec565b823411156120fd57604051600090339034869003908381818185875af1925050503d80600081146120aa576040519150601f19603f3d011682016040523d82523d6000602084013e6120af565b606091505b50509050806120f45760405162461bcd60e51b8152602060048201526011602482015270115512081c99599d5b990819985a5b1959607a1b60448201526064016107ec565b83915050612100565b50345b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561215b57600080fd5b505af115801561216f573d6000803e3d6000fd5b505050505092915050565b6040516001600160a01b038085166024830152831660448201526064810182905261145c9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261358c565b6001600160401b038416600090815260038701602052604081206122149061220f9086863361365e565b613808565b905060006122228683613865565b33600090815260048a016020526040902090915061224090826138a4565b508660030154421061225757612257888888612e6a565b604080516001600160801b0384168152336020820152600f87900b918101919091526060810185905283151560808201526001600160401b038716907f02270113c1297ab39d725cfb6962831ea118df963a68a6ce2fe974bef26954659060a0015b60405180910390a25050505050505050565b83548554600160481b909104600f90810b916000916122ec9184910b6138b0565b905060007f000000000000000000000000000000000000000000000000000000000000000061232857612323600f84900b836138e7565b612336565b612336600f84900b8361391a565b6006890154604051631b1aac9960e31b8152600f88810b600483015286810b602483015287900b60448201527f0000000000000000000000000000000000000000000000000000000000000000151560648201529192506001600160a01b03169063d8d564c890608401602060405180830381865afa1580156123bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123e19190615784565b6001880180546001600160801b0319166001600160801b03929092169190911790556006880154604051631b1aac9960e31b8152600f87810b600483015283810b602483015286900b60448201527f0000000000000000000000000000000000000000000000000000000000000000151560648201526001600160a01b039091169063d8d564c890608401602060405180830381865afa158015612489573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124ad9190615784565b6001880180546001600160801b03928316600160801b0292169190911790557f00000000000000000000000000000000000000000000000000000000000000001561255c57600187015461250490600f0b8661394d565b6001880180546001600160801b0319166001600160801b0392909216919091179081905561253c90600160801b9004600f0b8661394d565b6001880180546001600160801b03928316600160801b0292169190911790555b600187015460408051600f86810b825284810b602083015288810b9282019290925282820b6060820152600160801b909204900b60808201526001600160401b038716907f447e2e3d9b721c94b61250f439e96e626afd0552cb425d4c46da503a58096a779060a0016122b9565b60018201546000600f9190910b1315806125f4575060018201546000600160801b909104600f0b13155b8061261157506001820154600160801b8104600f90810b91900b13155b15612620576126208282612ca2565b5050565b60006002825460ff16600481111561263e5761263e615315565b148061265f57506003825460ff16600481111561265d5761265d615315565b145b8061267f57506004825460ff16600481111561267d5761267d615315565b145b15612691576002820154600f0b6107b5565b6107b582612d20565b60008060006126a7611e9b565b90506126b681600187876139a5565b92509250509250929050565b60006126cc611e9b565b54600f0b919050565b805460ff1660048111156126eb576126eb615315565b600114611efd5760405162461bcd60e51b81526004016107ec90615755565b60008083600f0b1361274b5760405162461bcd60e51b815260206004820152600a60248201526907072696365203c3d20360b41b60448201526064016107ec565b83600101548210156127905760405162461bcd60e51b815260206004820152600e60248201526d73697a65203c206d696e696d756d60901b60448201526064016107ec565b60006127a0600f85900b84612dd2565b95945050505050565b600034156128db576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166127e86020850185614f9d565b6001600160a01b0316146128305760405162461bcd60e51b815260206004820152600f60248201526e0e8ded6cadc92dc40427a40ee8aa89608b1b60448201526064016107ec565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561288b57600080fd5b505af115801561289f573d6000803e3d6000fd5b506128db9350506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016915086905034612e3a565b60208301351561290c5761290c3385602086018035906128fb9088614f9d565b6001600160a01b031692919061217a565b60006001600160a01b038516632e25a7ab61292a6020870187614f9d565b856129393460208a0135615890565b61294960808a0160608b01614f9d565b61295960a08b0160808c01614f9d565b61296660a08c018c6158be565b61297660e08e0160c08f01614f9d565b6040518963ffffffff1660e01b8152600401612999989796959493929190615914565b6020604051808303816000875af11580156129b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129dc919061597d565b90508360400135811015610c175760405162461bcd60e51b815260206004820152601c60248201527f6e6f7420656e6f756768206f75747075742066726f6d2074726164650000000060448201526064016107ec565b81831115612a7957610be181612a48848661573e565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169190612e3a565b82821115610be157610be18130610858868661573e565b600080612aa084600085336139a5565b91509150612ab084846000613391565b600080612abe868685613bb8565b915091508115612ae0578015612adb57612ad88185615890565b93505b600092505b8215612ba2576001600160401b0385166000908152600287016020526040808220600a01549051637921219560e11b815230600482015233602482015260448101919091526064810185905260a0608482015260a48101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f242432a9060c401600060405180830381600087803b158015612b8957600080fd5b505af1158015612b9d573d6000803e3d6000fd5b505050505b8315612bdc57612bdc6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163386612e3a565b60408051338152602081018690529081018490526001600160401b038616907f6c2dbbc7b415aab71b377f227d7a334f34899818306efbc6262b9ce85c4306be9060600160405180910390a2505050505050565b6000612c3a611e9b565b6001600160401b03909216600090815260029290920160205250604090206007015490565b612c67614e04565b6000612c71611e9b565b6001600160401b0385166000908152600391909101602052604090209050610c17816001600160801b03851661305b565b60006009830155612620826004835b82548290849060ff19166001836004811115612ccf57612ccf615315565b021790555082546040516001600160401b038316917f72d4affeac2e73f129f6fe359896ed8802d8bc11b826f9ac67cf50fcc7d3cc4d91612d139160ff169061534d565b60405180910390a2505050565b60038101546004820154600091908290612d3b90839061573e565b6001850154909150600f81810b91600160801b9004900b428410612d625750949350505050565b85600401544210612d765795945050505050565b6000612d82854261573e565b90506000612d908286613da8565b90506000612da2600f86900b856138e7565b90506000612db4600f84900b836138b0565b9050612dc4600f87900b826138e7565b9a9950505050505050505050565b600081612de1575060006107b5565b600083600f0b1215612df257600080fd5b600f83900b6001600160801b038316810260401c90608084901c026001600160c01b03811115612e2157600080fd5b60401b8119811115612e3257600080fd5b019392505050565b6040516001600160a01b038316602482015260448101829052610be190849063a9059cbb60e01b906064016121ae565b612e7482826125ca565b6004825460ff166004811115612e8c57612e8c615315565b14158015612ead5750612e9f8382613ddf565b80612ead5750816004015442115b15610be157600782015415612ed25760078201546008830155610be182600283612cb1565b610be18282612ca2565b6000612ee6611e9b565b6001600160401b03909216600090815260029290920160205250604090205460ff1690565b612f13614e38565b612f1b611e9b565b6001600160401b038316600090815260029190910160205260409081902081516101c081019092528054829060ff166004811115612f5b57612f5b615315565b6004811115612f6c57612f6c615315565b815281546101008082046001600160401b03166020840152600160481b909104600f90810b6040840152600184015480820b6060850152600160801b9004810b60808401526002840154900b60a0830152600383015460c0830152600483015460e08301526005830154908201526006820154610120820152600782015461014082015260088201546101608201526009820154610180820152600a909101546101a09091015292915050565b6000613023611e9b565b60010154905090565b6000613036611e9b565b6001600160401b03909216600090815260029290920160205250604090206006015490565b613063614e04565b506000908152600391820160209081526040918290208251608081018452815481526001820154600f0b928101929092526002810154928201929092529101546001600160a01b0316606082015290565b81546000908214156130cd576130ca8383613f45565b83555b6000828152600384016020526040812080548291829182919087146130fa576000955050505050506107b5565b600581015415158061310f5750600681015415155b156132cc5760058101541561314a578760030160006131358a84600001600001546141de565b81526020019081526020016000209450613172565b8760030160006131618a8460000160000154613f45565b815260200190815260200160002094505b6004850154600090815260038901602052604090208554600582015491955092508214156131ca57600685015460058501819055156131ca576006850154600090815260038901602052604090208454600482015592505b8454600685015414156132075760058501546006850181905515613207576005850154600090815260038901602052604090208454600482015592505b6004808201549086018190551561325f5760048101546000908152600389016020526040902081546005820154919550141561324557845460058501555b80546006850154141561325a57845460068501555b613267565b845460028901555b60058082015490860181905515613297576005810154600090815260038901602052604090208554600482015592505b600680820154908601819055156132c7576006810154600090815260038901602052604090208554600482015592505b613329565b6004810154156133215760048101546000908152600389016020526040902081546005820154919550141561330357600060058501555b80546006850154141561331857600060068501555b83549150613329565b600060028901555b60008082556001820180546001600160801b0319169055600282018190556003820180546001600160a01b031916905560048201819055600582018190556006820181905560078201558115613383576133838883614465565b506001979650505050505050565b3360009081526004840160205260408120905b6133ad8261344e565b8110156134475760006133c08383613458565b9050608081901c816001600160801b0386161580156133f05750866001600160401b0316826001600160401b0316145b806134285750856001600160801b0316816001600160801b03161480156134285750866001600160401b0316826001600160401b0316145b1561343957613437858461454c565b505b5050508060010190506133a4565b5050505050565b60006107b5825490565b60006112538383614558565b60008160030154116134b05760405162461bcd60e51b81526020600482015260156024820152741cdd185c9d081d1a5b59481a5cc81b9bdd081cd95d605a1b60448201526064016107ec565b8060030154421015611f065760405162461bcd60e51b8152602060048201526013602482015272185d58dd1a5bdb881b9bdd081cdd185c9d1959606a1b60448201526064016107ec565b60008160040154116135445760405162461bcd60e51b8152602060048201526013602482015272195b99081d1a5b59481a5cc81b9bdd081cd95d606a1b60448201526064016107ec565b8060040154421115611f065760405162461bcd60e51b8152602060048201526011602482015270185d58dd1a5bdb881a185cc8195b991959607a1b60448201526064016107ec565b60006135e1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166145de9092919063ffffffff16565b805190915015610be157808060200190518101906135ff9190615996565b610be15760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016107ec565b6000846001015460016136719190615890565b60018601819055855460009061368890889061305b565b602081015188549192509015806136a4575080600f0b87600f0b135b156136ad578288555b60008381526003890160205260409020548314156136fe576000838152600389016020526040902060010154600f88810b91900b14156136f257829350505050610c17565b6136fc88846130b4565b505b600088600201546000141561371557600289018490555b6002890154600090815260038a01602052604090205b805461378157848155600481018290556001810180546001600160801b0319166001600160801b038b16179055600281018890556003810180546001600160a01b0319166001600160a01b0389161790556137ed565b80546001820154909250600f90810b908a900b136137c35760068101546137aa57600681018590555b60060154600090815260038a016020526040902061372b565b60058101546137d457600581018590555b60050154600090815260038a016020526040902061372b565b80546137fa908b90614465565b509298975050505050505050565b60006001600160801b038211156138615760405162461bcd60e51b815260206004820152601c60248201527f53616665436173743a2076616c756520646f6573206e6f74206669740000000060448201526064016107ec565b5090565b60003060601b6001600160801b03831661389a67ffffffffffffffff60801b608087901b166001600160c01b03198416615890565b610c179190615890565b600061125383836145ed565b6000600f83810b9083900b0260401d60016001607f1b031981128015906138de575060016001607f1b038113155b61125357600080fd5b6000600f82810b9084900b0360016001607f1b031981128015906138de575060016001607f1b0381131561125357600080fd5b6000600f83810b9083900b0160016001607f1b031981128015906138de575060016001607f1b0381131561125357600080fd5b600081600f0b6000141561396057600080fd5b600082600f0b604085600f0b901b8161397b5761397b6159b8565b05905060016001607f1b031981128015906138de575060016001607f1b0381131561125357600080fd5b6001600160401b038216600090815260028501602090815260408083206003880190925282208291908280806139da85612624565b600886015490915060006139f66139ef875490565b879061305b565b90505b8051600090613a09908890613f45565b90508a6001600160a01b031682606001516001600160a01b03161415613b6157600080613a4a84604001518560200151600f0b612dd290919063ffffffff16565b905060048a5460ff166004811115613a6457613a64615315565b14158015613a725750600085115b8015613a88575085600f0b8460200151600f0b12155b15613b24576000613aa9856040015188600f0b612dd290919063ffffffff16565b90508585604001511115613ae457613ac5600f88900b87612dd2565b9050613ad18689615890565b9750613add8684615890565b9250613b08565b6040850151613af39089615890565b9750846040015183613b059190615890565b92505b613b12818361573e565b613b1c908a615890565b985050613b31565b613b2e8189615890565b97505b8e613b5e57818a6008016000828254613b4a919061573e565b90915550508351613b5c908a906130b4565b505b50505b8215613b8e578282604001511115613b7c5760009250613b8e565b6040820151613b8b908461573e565b92505b613b98878261305b565b8051909250151590506139f95750929b919a509098505050505050505050565b6001600160401b0380831660009081526002850160205260408120805491928392610100810490911690600160481b9004600f0b42821115613c035760008094509450505050613da0565b60405163098df99d60e11b81526001600160401b03831660048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063131bf33a90602401602060405180830381865afa158015613c73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c979190615784565b905060007f00000000000000000000000000000000000000000000000000000000000000008015613ccd575082600f0b82600f0b135b15613cf857613cf1886116a784613ce8600f82900b886138e7565b600f0b9061394d565b9050613d95565b7f0000000000000000000000000000000000000000000000000000000000000000158015613d2b575081600f0b83600f0b135b15613d95576000613d44896116a7600f87900b866138e7565b9050613d917f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008361463c565b9150505b600196509450505050505b935093915050565b600081613db457600080fd5b6000613dc08484614659565b905060016001607f1b036001600160801b038216111561125357600080fd5b6001600160401b038116600090815260038301602090815260408083206002860190925282206006810154613e3f576000613e19826147bb565b905060008111613e3957613e2d8286612ca2565b600093505050506107b5565b60068201555b6000806000613e56613e4f865490565b869061305b565b90505b8051600090613e69908790613f45565b9050613e7485612624565b600f0b8260200151600f0b1215613e8b5750613f12565b60068501546040830151613e9f9086615890565b10613ee15750602001516002840180546001600160801b0319166001600160801b039092169190911790555050600681015460079091015550600190506107b5565b6040820151613ef09085615890565b60208301519094509250613f04868261305b565b805190925015159050613e59575b506002830180546001600160801b0319166001600160801b03929092169190911790556007909101555060009392505050565b600081815260038301602052604081208054613f655760009150506107b5565b613f6d614ebd565b60068201541561409a5750600680820154600090815260038087016020908152604092839020835161012081018552815460a082019081526001830154600f0b60c0830152600283015460e0830152938201546001600160a01b03166101008201529283526004810154918301919091526005810154928201929092529181015460608301526007015460808201525b60408101511561408f5760409081015160009081526003808701602090815291839020835161012081018552815460a082019081526001830154600f0b60c0830152600283015460e0830152928201546001600160a01b031661010082015291825260048101549282019290925260058201549281019290925260068101546060830152600701546080820152613ffd565b515191506107b59050565b6004820154156141d357506004810154600081815260038087016020908152604092839020835161012081018552865460a082019081526001880154600f0b60c0830152600288015460e0830152938701546001600160a01b0316610100820152928352908201939093526005840154918101919091526006830154606082015260078301546080820152905b81515160058201541415614140575492506107b5915050565b600481015461414e576141d1565b6040805161012081018252825460a082019081526001840154600f0b60c0830152600284015460e08301526003808501546001600160a01b03166101008401529082526004840154602080840182905260058601548486015260068601546060850152600790950154608084015260009081529089019093529120909150614127565b505b506000949350505050565b6000818152600383016020526040812080546141fe5760009150506107b5565b614206614ebd565b60058201541561432e5750600580820154600090815260038087016020908152604092839020835161012081018552815460a082019081526001830154600f0b60c0830152600283015460e0830152938201546001600160a01b031661010082015292835260048101549183019190915292830154918101919091526006820154606082015260079091015460808201525b60608101511561408f57606090810151600090815260038087016020908152604092839020835161012081018552815460a082019081526001830154600f0b60c0830152600283015460e0830152938201546001600160a01b0316610100820152928352600481015491830191909152600581015492820192909252600682015492810192909252600701546080820152614298565b6004820154156141d357506004810154600081815260038087016020908152604092839020835161012081018552865460a082019081526001880154600f0b60c0830152600288015460e0830152938701546001600160a01b0316610100820152928352908201939093526005840154918101919091526006830154606082015260078301546080820152905b815151600682015414156143d4575492506107b5915050565b60048101546143e2576141d1565b6040805161012081018252825460a082019081526001840154600f0b60c0830152600284015460e08301526003808501546001600160a01b031661010084015290825260048401546020808401829052600586015484860152600686015460608501526007909501546080840152600090815290890190935291209091506143bb565b600081815260038301602052604090205b805460009061448690859061493c565b905080600214156144c35761449f84836005015461493c565b60001914156144b6576144b6848360050154614974565b81546144c3908590614a68565b8060011914156144fe576144db84836006015461493c565b600114156144f1576144f1848360060154614a68565b81546144fe908590614974565b8060001913158015614511575060018113155b15614523578154614523908590614b4b565b60048201546145325750505050565b506004015460009081526003830160205260409020614476565b60006112538383614b9a565b815460009082106145b65760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b60648201526084016107ec565b8260000182815481106145cb576145cb6158a8565b9060005260206000200154905092915050565b6060610c178484600085614c67565b6000818152600183016020526040812054614634575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556107b5565b5060006107b5565b6000806146498386614d67565b90506127a0600f82900b85614d7d565b60008161466557600080fd5b60006001600160c01b0384116146905782604085901b81614688576146886159b8565b0490506147a7565b60c084811c64010000000081106146a9576020918201911c5b6201000081106146bb576010918201911c5b61010081106146cc576008918201911c5b601081106146dc576004918201911c5b600481106146ec576002918201911c5b600281106146fb576001820191505b60bf820360018603901c6001018260ff0387901b8161471c5761471c6159b8565b0492506001600160801b0383111561473357600080fd5b608085901c83026001600160801b038616840260c088901c604089901b8281101561475f576001820391505b608084901b92900382811015614776576001820391505b829003608084901c821461478c5761478c6159ce565b88818161479b5761479b6159b8565b04870196505050505050505b6001600160801b0381111561125357600080fd5b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634ac8eb5f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561481c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614840919061597d565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a19471196040518163ffffffff1660e01b8152600401602060405180830381865afa1580156148a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148c6919061597d565b90508082116148d6576000610c17565b8354610c17907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090600160481b9004600f0b614934858761573e565b929190614d98565b6000818152600383016020526040808220600681015483528183206007908101546005830154855292842001549091610c17916159e4565b60008181526003830160205260409020600681015461499257600080fd5b6006810180546000908152600385016020526040812060048085015490820181905591909255156149fe576004820154600090815260038501602052604090208254600582015414156149e757815460058201555b8254600682015414156149fc57815460068201555b505b600581015415614a2d576005810154600090815260038501602052604090208054600684015582546004909101555b805460048084019190915582546005830155810154614a4e57805460028501555b8154614a5b908590614b4b565b805461145c908590614b4b565b600081815260038301602052604090206005810154614a8657600080fd5b600581018054600090815260038501602052604081206004808501549082018190559190925515614af257600482015460009081526003850160205260409020825460058201541415614adb57815460058201555b825460068201541415614af057815460068201555b505b600681015415614b2257600681015460008181526003860160205260409020600584019190915582546004909101555b805460048084019190915582546006830155810154614a4e57805460028501558154614a5b9085905b600081815260038301602052604080822060058101548352818320600790810154600683015485529290932090920154614b859190614dee565b614b90906001615890565b6007909101555050565b60008181526001830160205260408120548015614c5d57835460009085906000198101908110614bcc57614bcc6158a8565b9060005260206000200154905080856000016001840381548110614bf257614bf26158a8565b6000918252602080832090910192909255918252600186019052604090208190558354849080614c2457614c24615a23565b600190038181906000526020600020016000905590558360010160008481526020019081526020016000206000905560019150506107b5565b60009150506107b5565b6060843b614ccb5760405162461bcd60e51b815260206004820152602b60248201527f416464726573735574696c733a2066756e6374696f6e2063616c6c20746f206e60448201526a1bdb8b58dbdb9d1c9858dd60aa1b60648201526084016107ec565b600080866001600160a01b03168587604051614ce79190615a39565b60006040518083038185875af1925050503d8060008114614d24576040519150601f19603f3d011682016040523d82523d6000602084013e614d29565b606091505b50915091508115614d3d579150610c179050565b805115614d4d5780518082602001fd5b8360405162461bcd60e51b81526004016107ec9190615846565b600061125383614d7884600a615b39565b613da8565b6000611253614d8d83600a615b39565b600f85900b90612dd2565b600081600f0b60001415614dae57506000610c17565b8315614dbb575083610c17565b6000614dc78685614d67565b9050614de484614ddb600f84900b8661394d565b600f0b90614d7d565b9695505050505050565b6000818310614dfe5750816107b5565b50919050565b6040518060800160405280600081526020016000600f0b81526020016000815260200160006001600160a01b031681525090565b604080516101c08101909152806000815260200160006001600160401b031681526020016000600f0b81526020016000600f0b81526020016000600f0b81526020016000600f0b815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060a00160405280614ed0614e04565b8152602001600081526020016000815260200160008152602001600081525090565b600060208284031215614f0457600080fd5b81356001600160e01b03198116811461125357600080fd5b80356001600160401b0381168114614f3357600080fd5b919050565b600080600060608486031215614f4d57600080fd5b614f5684614f1c565b95602085013595506040909401359392505050565b600060208284031215614f7d57600080fd5b61125382614f1c565b80356001600160a01b0381168114614f3357600080fd5b600060208284031215614faf57600080fd5b61125382614f86565b80600f0b8114611f0657600080fd5b600060208284031215614fd957600080fd5b813561125381614fb8565b600060e08284031215614dfe57600080fd5b6000806000806080858703121561500c57600080fd5b84356001600160401b0381111561502257600080fd5b61502e87828801614fe4565b94505061503d60208601614f1c565b9250604085013561504d81614fb8565b9396929550929360600135925050565b6000806000806080858703121561507357600080fd5b84356001600160401b0381111561508957600080fd5b61509587828801614fe4565b9450506150a460208601614f1c565b93969395505050506040820135916060013590565b600080604083850312156150cc57600080fd5b6150d583614f1c565b915060208301356001600160801b03811681146150f157600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b0381118282101715615137576151376150fc565b6040525050565b600060c0828403121561515057600080fd5b60405160c081018181106001600160401b0382111715615172576151726150fc565b60405261517e83614f1c565b815261518c60208401614f1c565b6020820152604083013561519f81614fb8565b80604083015250606083013560608201526080830135608082015260a083013560a08201528091505092915050565b600080602083850312156151e157600080fd5b82356001600160401b03808211156151f857600080fd5b818501915085601f83011261520c57600080fd5b81358181111561521b57600080fd5b8660208260051b850101111561523057600080fd5b60209290920196919550909350505050565b60005b8381101561525d578181015183820152602001615245565b8381111561145c5750506000910152565b60008151808452615286816020860160208601615242565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156152ef57603f198886030184526152dd85835161526e565b945092850192908501906001016152c1565b5092979650505050505050565b60006020828403121561530e57600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b6005811061534957634e487b7160e01b600052602160045260246000fd5b9052565b602081016107b5828461532b565b60006101c08201905061536f82845161532b565b602083015161538960208401826001600160401b03169052565b50604083015161539e6040840182600f0b9052565b5060608301516153b36060840182600f0b9052565b5060808301516153c86080840182600f0b9052565b5060a08301516153dd60a0840182600f0b9052565b5060c0838101519083015260e08084015190830152610100808401519083015261012080840151908301526101408084015190830152610160808401519083015261018080840151908301526101a092830151929091019190915290565b600082601f83011261544c57600080fd5b813560206001600160401b03821115615467576154676150fc565b8160051b60405161547a83830182615112565b9283528481018201928281018785111561549357600080fd5b83870192505b848310156154b05782358152918301918301615499565b509695505050505050565b600082601f8301126154cc57600080fd5b81356001600160401b038111156154e5576154e56150fc565b6040516154fc601f8301601f191660200182615112565b81815284602083860101111561551157600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a0868803121561554657600080fd5b61554f86614f86565b945061555d60208701614f86565b935060408601356001600160401b038082111561557957600080fd5b61558589838a0161543b565b9450606088013591508082111561559b57600080fd5b6155a789838a0161543b565b935060808801359150808211156155bd57600080fd5b506155ca888289016154bb565b9150509295509295909350565b6000806000606084860312156155ec57600080fd5b6155f584614f1c565b9250602084013561560581614fb8565b929592945050506040919091013590565b6000806040838503121561562957600080fd5b61563283614f1c565b915061564060208401614f86565b90509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561568157835183529284019291840191600101615665565b50909695505050505050565b600080600080600060a086880312156156a557600080fd5b6156ae86614f86565b94506156bc60208701614f86565b9350604086013592506060860135915060808601356001600160401b038111156156e557600080fd5b6155ca888289016154bb565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008282101561575057615750615728565b500390565b6020808252601590820152741cdd185d1d5cc8084f481a5b9a5d1a585b1a5e9959605a1b604082015260600190565b60006020828403121561579657600080fd5b815161125381614fb8565b600060033d11156157ba5760046000803e5060005160e01c5b90565b600060443d10156157cb5790565b6040516003193d81016004833e81513d6001600160401b0381602484011181841117156157fa57505050505090565b82850191508151818111156158125750505050505090565b843d870101602082850101111561582c5750505050505090565b61583b60208286010187615112565b509095945050505050565b602081526000611253602083018461526e565b6020808252601d908201527f4f776e61626c653a2073656e646572206d757374206265206f776e6572000000604082015260600190565b600082198211156158a3576158a3615728565b500190565b634e487b7160e01b600052603260045260246000fd5b6000808335601e198436030181126158d557600080fd5b8301803591506001600160401b038211156158ef57600080fd5b602001915036819003821315611dce57600080fd5b8183823760009101908152919050565b600060018060a01b03808b168352808a1660208401528860408401528088166060840152808716608084015260e060a08401528460e08401526101008587828601376000848701820152931660c083015250601f909201601f1916909101019695505050505050565b60006020828403121561598f57600080fd5b5051919050565b6000602082840312156159a857600080fd5b8151801515811461125357600080fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b60008083128015600160ff1b850184121615615a0257615a02615728565b6001600160ff1b0384018313811615615a1d57615a1d615728565b50500390565b634e487b7160e01b600052603160045260246000fd5b60008251615a4b818460208701615242565b9190910192915050565b600181815b80851115615a90578160001904821115615a7657615a76615728565b80851615615a8357918102915b93841c9390800290615a5a565b509250929050565b600082615aa7575060016107b5565b81615ab4575060006107b5565b8160018114615aca5760028114615ad457615af0565b60019150506107b5565b60ff841115615ae557615ae5615728565b50506001821b6107b5565b5060208310610133831016604e8410600b8410161715615b13575081810a6107b5565b615b1d8383615a55565b8060001904821115615b3157615b31615728565b029392505050565b600061125360ff841683615a9856fe8a22373512790c48b83a1fe2efdd2888d4a917bcdc24d0adf63e60f67168046009acf4e54214992e70883cf7dcd6957ff2c71cd9e14df4bec4383bc0d11607dca264697066735822122071520f7a01fd7d370bd739d9cd965a8238fb4730007d5c800318f6424844443c64736f6c634300080c00330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e5dbc4edf467b609a063c7ea7fab976c6b9baa1a00000000000000000000000082900b0495303216d128d4770de425e0a3c14c1f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1

Deployed Bytecode

0x6080604052600436106102045760003560e01c8063a16594b911610118578063cc4aa204116100a0578063d3f44d841161006f578063d3f44d84146106bf578063d999ec8f146106df578063da60d637146106ff578063df4c96701461071f578063f23a6e611461074c57600080fd5b8063cc4aa20414610643578063d07041e014610677578063d2639b621461068c578063d26fef61146106ac57600080fd5b8063b670b058116100e7578063b670b05814610564578063ba728b5f14610584578063ba98d741146105a4578063bc12e3d7146105d1578063bc197c81146105fe57600080fd5b8063a16594b9146104c3578063ac9650d8146104e3578063ad5c464814610510578063b044ab751461054457600080fd5b80632d2c44f21161019b57806379e1aa381161016a57806379e1aa38146103e35780637a4f8d3a146103f65780637e28e8bf146104245780637f32cf41146104445780638df5db82146104a357600080fd5b80632d2c44f21461036757806357530e871461039b578063579e792f146103b0578063750f0acc146103c357600080fd5b806321651f8e116101d757806321651f8e146102bf57806327f39951146102f257806329390370146103275780632a0d3a291461034757600080fd5b806301ffc9a71461020957806307f3b8bb1461023e5780630cfd168f1461028a57806318f4a50a1461029f575b600080fd5b34801561021557600080fd5b50610229610224366004614ef2565b610778565b60405190151581526020015b60405180910390f35b34801561024a57600080fd5b506102727f000000000000000000000000e5dbc4edf467b609a063c7ea7fab976c6b9baa1a81565b6040516001600160a01b039091168152602001610235565b61029d610298366004614f38565b6107bb565b005b3480156102ab57600080fd5b5061029d6102ba366004614f6b565b6108a8565b3480156102cb57600080fd5b506102df6102da366004614f6b565b610be6565b604051600f9190910b8152602001610235565b3480156102fe57600080fd5b5061031261030d366004614f6b565b610c1f565b60408051928352602083019190915201610235565b34801561033357600080fd5b5061029d610342366004614f9d565b610c35565b34801561035357600080fd5b5061029d610362366004614fc7565b610d8f565b34801561037357600080fd5b506102727f00000000000000000000000082900b0495303216d128d4770de425e0a3c14c1f81565b3480156103a757600080fd5b506102df610ec0565b61029d6103be366004614ff6565b610ecf565b3480156103cf57600080fd5b5061029d6103de366004614f6b565b610fab565b61029d6103f136600461505d565b61111f565b34801561040257600080fd5b50610416610411366004614f6b565b611200565b604051908152602001610235565b34801561043057600080fd5b506102df61043f366004614f6b565b61120b565b34801561045057600080fd5b5061046461045f3660046150b9565b611241565b604051610235919081518152602080830151600f0b90820152604080830151908201526060918201516001600160a01b03169181019190915260800190565b3480156104af57600080fd5b5061029d6104be36600461513e565b61125a565b3480156104cf57600080fd5b506102df6104de366004614f6b565b611462565b3480156104ef57600080fd5b506105036104fe3660046151ce565b611493565b604051610235919061529a565b34801561051c57600080fd5b506102727f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab181565b34801561055057600080fd5b5061031261055f366004614f6b565b61159e565b34801561057057600080fd5b5061029d61057f3660046152fc565b611735565b34801561059057600080fd5b5061029d61059f366004614f6b565b611809565b3480156105b057600080fd5b506105c46105bf366004614f6b565b6118cd565b604051610235919061534d565b3480156105dd57600080fd5b506105f16105ec366004614f6b565b6118d8565b604051610235919061535b565b34801561060a57600080fd5b5061062a61061936600461552e565b63bc197c8160e01b95945050505050565b6040516001600160e01b03199091168152602001610235565b34801561064f57600080fd5b506102727f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da181565b34801561068357600080fd5b506104166118e9565b34801561069857600080fd5b506104166106a7366004614f6b565b6118f3565b61029d6106ba3660046155d7565b61194b565b3480156106cb57600080fd5b5061029d6106da3660046150b9565b6119f8565b3480156106eb57600080fd5b5061029d6106fa366004614f9d565b611c62565b34801561070b57600080fd5b5061031261071a366004615616565b611dbc565b34801561072b57600080fd5b5061073f61073a366004614f9d565b611dd5565b6040516102359190615649565b34801561075857600080fd5b5061062a61076736600461568d565b63f23a6e6160e01b95945050505050565b6001600160e01b0319811660009081527f326d0c59a7612f6a9919e2a8ee333c80ba689d8ba2634de89c85cbb04832e705602052604081205460ff165b92915050565b600080516020615b698339815191528054600214156107f55760405162461bcd60e51b81526004016107ec906156f1565b60405180910390fd5b600281556000610803611e9b565b6001600160401b0386166000908152600282016020526040902090915061082981611ebf565b60008061083884848989611f09565b91509150600061084782611fbe565b905061088a3330610858848661573e565b6001600160a01b037f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da11692919061217a565b61089985858b868c60006121e5565b50506001909355505050505050565b60006108b2611e9b565b6001600160401b0383166000908152600282016020526040902080549192509060ff1660048111156108e6576108e6615315565b6001146109055760405162461bcd60e51b81526004016107ec90615755565b6107088160030154610917919061573e565b421161095b5760405162461bcd60e51b815260206004820152601360248201527270726963652073657420746f6f206561726c7960681b60448201526064016107ec565b60018101546000600160801b909104600f0b131580610985575060018101546000600f9190910b13155b6109ca5760405162461bcd60e51b81526020600482015260166024820152751c1c9a58d95cc8185c9948185b1c9958591e481cd95d60521b60448201526064016107ec565b4281600301541115610bd7576000808360060160009054906101000a90046001600160a01b03166001600160a01b031663d33b48b56040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610a4a575060408051601f3d908101601f19168201909252610a4791810190615784565b60015b610ac357610a566157a1565b806308c379a01415610ab75750610a6b6157bd565b80610a765750610ab9565b7fcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab81604051610aa59190615846565b60405180910390a16000925050610ac6565b505b3d6000803e3d6000fd5b91505b60068401548354604051631d94c9b360e01b81526101009091046001600160401b031660048201526001600160a01b0390911690631d94c9b390602401602060405180830381865afa925050508015610b3c575060408051601f3d908101601f19168201909252610b3991810190615784565b60015b610ba957610b486157a1565b806308c379a01415610ab75750610b5d6157bd565b80610b685750610ab9565b7fcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab81604051610b979190615846565b60405180910390a16000915050610bac565b90505b600082600f0b138015610bc25750600081600f0b135b15610bd457610bd484848785856122cb565b50505b610be181846125ca565b505050565b600080610bf1611e9b565b6001600160401b03841660009081526002820160205260409020909150610c1781612624565b949350505050565b600080610c2c833361269a565b91509150915091565b600080516020615b49833981519152546001600160a01b03163314610c6c5760405162461bcd60e51b81526004016107ec90615859565b6000610c76611e9b565b90506001600160a01b038216610cc55760405162461bcd60e51b81526020600482015260146024820152731859191c995cdcc81b9bdd081c1c9bdd9a59195960621b60448201526064016107ec565b60068101546001600160a01b0383811691161415610d1e5760405162461bcd60e51b81526020600482015260166024820152751b995dc81859191c995cdcc8195c5d585b1cc81bdb1960521b60448201526064016107ec565b6006810154604080516001600160a01b03928316815291841660208301523382820152517faa40df73b7e66d2e4e3a90deb47486303ca82739a96c5595ba8c68d00482fed29181900360600190a160060180546001600160a01b0319166001600160a01b0392909216919091179055565b600080516020615b49833981519152546001600160a01b03163314610dc65760405162461bcd60e51b81526004016107ec90615859565b6000610dd0611e9b565b9050600082600f0b13610e125760405162461bcd60e51b815260206004820152600a602482015269064656c7461203c3d20360b41b60448201526064016107ec565b68010000000000000000600f83900b12610e5a5760405162461bcd60e51b815260206004820152600960248201526864656c7461203e203160b81b60448201526064016107ec565b805460408051600f92830b81529184900b60208301523382820152517f8ade3304a9dbce06100c268f7f1f6e66c1627bf10e8a495977290d0625148eb99181900360600190a180546001600160801b0319166001600160801b0392909216919091179055565b6000610eca6126c2565b905090565b600080516020615b69833981519152805460021415610f005760405162461bcd60e51b81526004016107ec906156f1565b600281556000610f0e611e9b565b6001600160401b03861660009081526002820160205260409020909150610f34816126d5565b6000610f4183878761270a565b6005840154909150600090610f80906001600160a01b03168a7f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da16127a9565b9050610f8d818333612a32565b610f9c84848a8a8a60016121e5565b50506001909255505050505050565b600080516020615b69833981519152805460021415610fdc5760405162461bcd60e51b81526004016107ec906156f1565b600281556000610fea611e9b565b6001600160401b0384166000908152600282016020526040902080549192509060ff16600481111561101e5761101e615315565b600314806110415750805460ff16600481111561103d5761103d615315565b6004145b61108d5760405162461bcd60e51b815260206004820181905260248201527f73746174757320213d2070726f636573736564207c7c2063616e63656c6c656460448201526064016107ec565b805460ff1660048111156110a3576110a3615315565b6003141561110c5760058101546110bd9062015180615890565b42101561110c5760405162461bcd60e51b815260206004820152601960248201527f686f6c6420706572696f6420686173206e6f7420656e6465640000000000000060448201526064016107ec565b6111168285612a90565b50506001905550565b600080516020615b698339815191528054600214156111505760405162461bcd60e51b81526004016107ec906156f1565b60028155600061115e611e9b565b6001600160401b0386166000908152600282016020526040902090915061118481611ebf565b60008061119384848989611f09565b600586015491935091506000906111d4906001600160a01b03168b7f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da16127a9565b90506111e1818333612a32565b6111f085858b868c60006121e5565b5050600190935550505050505050565b60006107b582612c30565b600080611216611e9b565b6001600160401b03841660009081526002820160205260409020909150610c178160020154600f0b90565b611249614e04565b6112538383612c5f565b9392505050565b6000611264611e9b565b9050336001600160a01b037f00000000000000000000000082900b0495303216d128d4770de425e0a3c14c1f16146112c75760405162461bcd60e51b8152602060048201526006602482015265085d985d5b1d60d21b60448201526064016107ec565b60006112d1611e9b565b83516001600160401b031660009081526002820160205260408120919250815460ff16600481111561130557611305615315565b146113525760405162461bcd60e51b815260206004820152601760248201527f73746174757320213d20756e696e697469616c697a656400000000000000000060448201526064016107ec565b8360a00151846080015110158061136c5750836080015142115b80611383575083602001516001600160401b031642115b80611396575060008460400151600f0b13155b806113a357506060840151155b156113d45783516001600160401b03166000908152600283016020526040902084516113cf9190612ca2565b61145c565b6020840151815460408601516001600160801b0316600160481b0278ffffffffffffffffffffffffffffffff000000000000000000196001600160401b039093166101000292909216610100600160c81b0319909116171781556080840151600382015560a084015160048201556060840151600a820155835161145c908290600190612cb1565b50505050565b60008061146d611e9b565b6001600160401b03841660009081526002820160205260409020909150610c1781612d20565b6060816001600160401b038111156114ad576114ad6150fc565b6040519080825280602002602001820160405280156114e057816020015b60608152602001906001900390816114cb5790505b50905060005b828110156115975760008030868685818110611504576115046158a8565b905060200281019061151691906158be565b604051611524929190615904565b600060405180830381855af49150503d806000811461155f576040519150601f19603f3d011682016040523d82523d6000602084013e611564565b606091505b50915091508115610ab95780848481518110611582576115826158a8565b602002602001018190525050506001016114e6565b5092915050565b60008060006115ab611e9b565b9050336001600160a01b037f00000000000000000000000082900b0495303216d128d4770de425e0a3c14c1f161461160e5760405162461bcd60e51b8152602060048201526006602482015265085d985d5b1d60d21b60448201526064016107ec565b6000611618611e9b565b6001600160401b0386166000908152600282016020526040902080549192509060ff16600481111561164c5761164c615315565b6002146116915760405162461bcd60e51b81526020600482015260136024820152721cdd185d1d5cc8084f48199a5b985b1a5e9959606a1b60448201526064016107ec565b6116b081600701546116a78360020154600f0b90565b600f0b90612dd2565b6009820181905561170d906001600160a01b037f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da116907f00000000000000000000000082900b0495303216d128d4770de425e0a3c14c1f90612e3a565b42600582015561171f81600388612cb1565b8060090154816007015494509450505050915091565b600080516020615b49833981519152546001600160a01b0316331461176c5760405162461bcd60e51b81526004016107ec90615859565b6000611776611e9b565b9050600082116117c05760405162461bcd60e51b815260206004820152601560248201527476616c75652065786365656473206d696e696d756d60581b60448201526064016107ec565b600181015460408051918252602082018490523382820152517f1f1913f02d98f08a2ed8c776d0559838fe3804f17663b57486c274065646ceb99181900360600190a160010155565b6000611813611e9b565b6001600160401b038316600090815260028201602052604090206004810154919250906118439062015180615890565b4211801561188557506001815460ff16600481111561186457611864615315565b148061188557506002815460ff16600481111561188357611883615315565b145b1561189457610be18184612ca2565b806003015442101580156118bd57506001815460ff1660048111156118bb576118bb615315565b145b15610be157610be1828285612e6a565b60006107b582612edc565b6118e0614e38565b6107b582612f0b565b6000610eca613019565b6000806118fe611e9b565b6001600160401b0384166000908152600282016020526040902060038101549192509015801590611933575080600301544210155b1561194157610c178461302c565b5060009392505050565b600080516020615b6983398151915280546002141561197c5760405162461bcd60e51b81526004016107ec906156f1565b60028155600061198a611e9b565b6001600160401b038616600090815260028201602052604090209091506119b0816126d5565b60006119bd83878761270a565b905060006119ca82611fbe565b90506119db3330610858848661573e565b6119ea84848a8a8a60016121e5565b505060019092555050505050565b600080516020615b69833981519152805460021415611a295760405162461bcd60e51b81526004016107ec906156f1565b600281556000611a37611e9b565b6001600160401b03851660009081526002820160205260409020909150611a5d816126d5565b6000846001600160801b031611611aa95760405162461bcd60e51b815260206004820152601060248201526f1a5b9d985b1a59081bdc99195c881a5960821b60448201526064016107ec565b6001600160401b0385166000908152600383016020526040812090611ad7826001600160801b03881661305b565b60608101519091506001600160a01b0316611b2b5760405162461bcd60e51b81526020600482015260146024820152731bdc99195c88191bd95cc81b9bdd08195e1a5cdd60621b60448201526064016107ec565b60608101516001600160a01b03163314611b7d5760405162461bcd60e51b8152602060048201526013602482015272313abcb2b910109e9036b9b39739b2b73232b960691b60448201526064016107ec565b611b90826001600160801b0388166130b4565b50611b9c848888613391565b82600301544210611bb257611bb2848489612e6a565b6000611bd282604001518360200151600f0b612dd290919063ffffffff16565b9050611c086001600160a01b037f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da1163383612e3a565b604080516001600160801b03891681523360208201526001600160401b038a16917fb7a419a9cad0cf4a1610023a7ee67f873ba51a63189b14b543ee6f31db8b7f3c910160405180910390a2505060019093555050505050565b600080516020615b49833981519152546001600160a01b03163314611c995760405162461bcd60e51b81526004016107ec90615859565b6000611ca3611e9b565b90506001600160a01b038216611cf25760405162461bcd60e51b81526020600482015260146024820152731859191c995cdcc81b9bdd081c1c9bdd9a59195960621b60448201526064016107ec565b60058101546001600160a01b0383811691161415611d4b5760405162461bcd60e51b81526020600482015260166024820152751b995dc81859191c995cdcc8195c5d585b1cc81bdb1960521b60448201526064016107ec565b6005810154604080516001600160a01b03928316815291841660208301523382820152517f045d485de10addb86db6ce795700266572ef7d9132df09a384062b5e82a093739181900360600190a160050180546001600160a01b0319166001600160a01b0392909216919091179055565b600080611dc9848461269a565b915091505b9250929050565b60606000611de1611e9b565b6001600160a01b03841660009081526004820160205260408120919250611e078261344e565b6001600160401b03811115611e1e57611e1e6150fc565b604051908082528060200260200182016040528015611e47578160200160208202803683370190505b50905060005b611e568361344e565b811015611e92576000611e698483613458565b905080838381518110611e7e57611e7e6158a8565b602090810291909101015250600101611e4d565b50949350505050565b7f7f75137652cf01fd4e0a016c479a4a2bdc1018772b7fc0eab68410c366c40cbb90565b805460ff166004811115611ed557611ed5615315565b600114611ef45760405162461bcd60e51b81526004016107ec90615755565b611efd81613464565b611f06816134fa565b50565b6000808560010154841015611f515760405162461bcd60e51b815260206004820152600e60248201526d73697a65203c206d696e696d756d60901b60448201526064016107ec565b6000611f5c86612d20565b90506000611f6e600f83900b87612dd2565b905080851015611fb15760405162461bcd60e51b815260206004820152600e60248201526d18dbdcdd080f881b585e10dbdcdd60921b60448201526064016107ec565b9097909650945050505050565b60008034156107b5577f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b03167f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da16001600160a01b03161461205d5760405162461bcd60e51b81526020600482015260126024820152710c6ded8d8c2e8cae4c2d840427a40ee8aa8960731b60448201526064016107ec565b823411156120fd57604051600090339034869003908381818185875af1925050503d80600081146120aa576040519150601f19603f3d011682016040523d82523d6000602084013e6120af565b606091505b50509050806120f45760405162461bcd60e51b8152602060048201526011602482015270115512081c99599d5b990819985a5b1959607a1b60448201526064016107ec565b83915050612100565b50345b7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561215b57600080fd5b505af115801561216f573d6000803e3d6000fd5b505050505092915050565b6040516001600160a01b038085166024830152831660448201526064810182905261145c9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261358c565b6001600160401b038416600090815260038701602052604081206122149061220f9086863361365e565b613808565b905060006122228683613865565b33600090815260048a016020526040902090915061224090826138a4565b508660030154421061225757612257888888612e6a565b604080516001600160801b0384168152336020820152600f87900b918101919091526060810185905283151560808201526001600160401b038716907f02270113c1297ab39d725cfb6962831ea118df963a68a6ce2fe974bef26954659060a0015b60405180910390a25050505050505050565b83548554600160481b909104600f90810b916000916122ec9184910b6138b0565b905060007f000000000000000000000000000000000000000000000000000000000000000061232857612323600f84900b836138e7565b612336565b612336600f84900b8361391a565b6006890154604051631b1aac9960e31b8152600f88810b600483015286810b602483015287900b60448201527f0000000000000000000000000000000000000000000000000000000000000000151560648201529192506001600160a01b03169063d8d564c890608401602060405180830381865afa1580156123bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123e19190615784565b6001880180546001600160801b0319166001600160801b03929092169190911790556006880154604051631b1aac9960e31b8152600f87810b600483015283810b602483015286900b60448201527f0000000000000000000000000000000000000000000000000000000000000000151560648201526001600160a01b039091169063d8d564c890608401602060405180830381865afa158015612489573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124ad9190615784565b6001880180546001600160801b03928316600160801b0292169190911790557f00000000000000000000000000000000000000000000000000000000000000001561255c57600187015461250490600f0b8661394d565b6001880180546001600160801b0319166001600160801b0392909216919091179081905561253c90600160801b9004600f0b8661394d565b6001880180546001600160801b03928316600160801b0292169190911790555b600187015460408051600f86810b825284810b602083015288810b9282019290925282820b6060820152600160801b909204900b60808201526001600160401b038716907f447e2e3d9b721c94b61250f439e96e626afd0552cb425d4c46da503a58096a779060a0016122b9565b60018201546000600f9190910b1315806125f4575060018201546000600160801b909104600f0b13155b8061261157506001820154600160801b8104600f90810b91900b13155b15612620576126208282612ca2565b5050565b60006002825460ff16600481111561263e5761263e615315565b148061265f57506003825460ff16600481111561265d5761265d615315565b145b8061267f57506004825460ff16600481111561267d5761267d615315565b145b15612691576002820154600f0b6107b5565b6107b582612d20565b60008060006126a7611e9b565b90506126b681600187876139a5565b92509250509250929050565b60006126cc611e9b565b54600f0b919050565b805460ff1660048111156126eb576126eb615315565b600114611efd5760405162461bcd60e51b81526004016107ec90615755565b60008083600f0b1361274b5760405162461bcd60e51b815260206004820152600a60248201526907072696365203c3d20360b41b60448201526064016107ec565b83600101548210156127905760405162461bcd60e51b815260206004820152600e60248201526d73697a65203c206d696e696d756d60901b60448201526064016107ec565b60006127a0600f85900b84612dd2565b95945050505050565b600034156128db576001600160a01b037f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1166127e86020850185614f9d565b6001600160a01b0316146128305760405162461bcd60e51b815260206004820152600f60248201526e0e8ded6cadc92dc40427a40ee8aa89608b1b60448201526064016107ec565b7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561288b57600080fd5b505af115801561289f573d6000803e3d6000fd5b506128db9350506001600160a01b037f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab116915086905034612e3a565b60208301351561290c5761290c3385602086018035906128fb9088614f9d565b6001600160a01b031692919061217a565b60006001600160a01b038516632e25a7ab61292a6020870187614f9d565b856129393460208a0135615890565b61294960808a0160608b01614f9d565b61295960a08b0160808c01614f9d565b61296660a08c018c6158be565b61297660e08e0160c08f01614f9d565b6040518963ffffffff1660e01b8152600401612999989796959493929190615914565b6020604051808303816000875af11580156129b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129dc919061597d565b90508360400135811015610c175760405162461bcd60e51b815260206004820152601c60248201527f6e6f7420656e6f756768206f75747075742066726f6d2074726164650000000060448201526064016107ec565b81831115612a7957610be181612a48848661573e565b6001600160a01b037f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da1169190612e3a565b82821115610be157610be18130610858868661573e565b600080612aa084600085336139a5565b91509150612ab084846000613391565b600080612abe868685613bb8565b915091508115612ae0578015612adb57612ad88185615890565b93505b600092505b8215612ba2576001600160401b0385166000908152600287016020526040808220600a01549051637921219560e11b815230600482015233602482015260448101919091526064810185905260a0608482015260a48101919091527f000000000000000000000000e5dbc4edf467b609a063c7ea7fab976c6b9baa1a6001600160a01b03169063f242432a9060c401600060405180830381600087803b158015612b8957600080fd5b505af1158015612b9d573d6000803e3d6000fd5b505050505b8315612bdc57612bdc6001600160a01b037f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da1163386612e3a565b60408051338152602081018690529081018490526001600160401b038616907f6c2dbbc7b415aab71b377f227d7a334f34899818306efbc6262b9ce85c4306be9060600160405180910390a2505050505050565b6000612c3a611e9b565b6001600160401b03909216600090815260029290920160205250604090206007015490565b612c67614e04565b6000612c71611e9b565b6001600160401b0385166000908152600391909101602052604090209050610c17816001600160801b03851661305b565b60006009830155612620826004835b82548290849060ff19166001836004811115612ccf57612ccf615315565b021790555082546040516001600160401b038316917f72d4affeac2e73f129f6fe359896ed8802d8bc11b826f9ac67cf50fcc7d3cc4d91612d139160ff169061534d565b60405180910390a2505050565b60038101546004820154600091908290612d3b90839061573e565b6001850154909150600f81810b91600160801b9004900b428410612d625750949350505050565b85600401544210612d765795945050505050565b6000612d82854261573e565b90506000612d908286613da8565b90506000612da2600f86900b856138e7565b90506000612db4600f84900b836138b0565b9050612dc4600f87900b826138e7565b9a9950505050505050505050565b600081612de1575060006107b5565b600083600f0b1215612df257600080fd5b600f83900b6001600160801b038316810260401c90608084901c026001600160c01b03811115612e2157600080fd5b60401b8119811115612e3257600080fd5b019392505050565b6040516001600160a01b038316602482015260448101829052610be190849063a9059cbb60e01b906064016121ae565b612e7482826125ca565b6004825460ff166004811115612e8c57612e8c615315565b14158015612ead5750612e9f8382613ddf565b80612ead5750816004015442115b15610be157600782015415612ed25760078201546008830155610be182600283612cb1565b610be18282612ca2565b6000612ee6611e9b565b6001600160401b03909216600090815260029290920160205250604090205460ff1690565b612f13614e38565b612f1b611e9b565b6001600160401b038316600090815260029190910160205260409081902081516101c081019092528054829060ff166004811115612f5b57612f5b615315565b6004811115612f6c57612f6c615315565b815281546101008082046001600160401b03166020840152600160481b909104600f90810b6040840152600184015480820b6060850152600160801b9004810b60808401526002840154900b60a0830152600383015460c0830152600483015460e08301526005830154908201526006820154610120820152600782015461014082015260088201546101608201526009820154610180820152600a909101546101a09091015292915050565b6000613023611e9b565b60010154905090565b6000613036611e9b565b6001600160401b03909216600090815260029290920160205250604090206006015490565b613063614e04565b506000908152600391820160209081526040918290208251608081018452815481526001820154600f0b928101929092526002810154928201929092529101546001600160a01b0316606082015290565b81546000908214156130cd576130ca8383613f45565b83555b6000828152600384016020526040812080548291829182919087146130fa576000955050505050506107b5565b600581015415158061310f5750600681015415155b156132cc5760058101541561314a578760030160006131358a84600001600001546141de565b81526020019081526020016000209450613172565b8760030160006131618a8460000160000154613f45565b815260200190815260200160002094505b6004850154600090815260038901602052604090208554600582015491955092508214156131ca57600685015460058501819055156131ca576006850154600090815260038901602052604090208454600482015592505b8454600685015414156132075760058501546006850181905515613207576005850154600090815260038901602052604090208454600482015592505b6004808201549086018190551561325f5760048101546000908152600389016020526040902081546005820154919550141561324557845460058501555b80546006850154141561325a57845460068501555b613267565b845460028901555b60058082015490860181905515613297576005810154600090815260038901602052604090208554600482015592505b600680820154908601819055156132c7576006810154600090815260038901602052604090208554600482015592505b613329565b6004810154156133215760048101546000908152600389016020526040902081546005820154919550141561330357600060058501555b80546006850154141561331857600060068501555b83549150613329565b600060028901555b60008082556001820180546001600160801b0319169055600282018190556003820180546001600160a01b031916905560048201819055600582018190556006820181905560078201558115613383576133838883614465565b506001979650505050505050565b3360009081526004840160205260408120905b6133ad8261344e565b8110156134475760006133c08383613458565b9050608081901c816001600160801b0386161580156133f05750866001600160401b0316826001600160401b0316145b806134285750856001600160801b0316816001600160801b03161480156134285750866001600160401b0316826001600160401b0316145b1561343957613437858461454c565b505b5050508060010190506133a4565b5050505050565b60006107b5825490565b60006112538383614558565b60008160030154116134b05760405162461bcd60e51b81526020600482015260156024820152741cdd185c9d081d1a5b59481a5cc81b9bdd081cd95d605a1b60448201526064016107ec565b8060030154421015611f065760405162461bcd60e51b8152602060048201526013602482015272185d58dd1a5bdb881b9bdd081cdd185c9d1959606a1b60448201526064016107ec565b60008160040154116135445760405162461bcd60e51b8152602060048201526013602482015272195b99081d1a5b59481a5cc81b9bdd081cd95d606a1b60448201526064016107ec565b8060040154421115611f065760405162461bcd60e51b8152602060048201526011602482015270185d58dd1a5bdb881a185cc8195b991959607a1b60448201526064016107ec565b60006135e1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166145de9092919063ffffffff16565b805190915015610be157808060200190518101906135ff9190615996565b610be15760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016107ec565b6000846001015460016136719190615890565b60018601819055855460009061368890889061305b565b602081015188549192509015806136a4575080600f0b87600f0b135b156136ad578288555b60008381526003890160205260409020548314156136fe576000838152600389016020526040902060010154600f88810b91900b14156136f257829350505050610c17565b6136fc88846130b4565b505b600088600201546000141561371557600289018490555b6002890154600090815260038a01602052604090205b805461378157848155600481018290556001810180546001600160801b0319166001600160801b038b16179055600281018890556003810180546001600160a01b0319166001600160a01b0389161790556137ed565b80546001820154909250600f90810b908a900b136137c35760068101546137aa57600681018590555b60060154600090815260038a016020526040902061372b565b60058101546137d457600581018590555b60050154600090815260038a016020526040902061372b565b80546137fa908b90614465565b509298975050505050505050565b60006001600160801b038211156138615760405162461bcd60e51b815260206004820152601c60248201527f53616665436173743a2076616c756520646f6573206e6f74206669740000000060448201526064016107ec565b5090565b60003060601b6001600160801b03831661389a67ffffffffffffffff60801b608087901b166001600160c01b03198416615890565b610c179190615890565b600061125383836145ed565b6000600f83810b9083900b0260401d60016001607f1b031981128015906138de575060016001607f1b038113155b61125357600080fd5b6000600f82810b9084900b0360016001607f1b031981128015906138de575060016001607f1b0381131561125357600080fd5b6000600f83810b9083900b0160016001607f1b031981128015906138de575060016001607f1b0381131561125357600080fd5b600081600f0b6000141561396057600080fd5b600082600f0b604085600f0b901b8161397b5761397b6159b8565b05905060016001607f1b031981128015906138de575060016001607f1b0381131561125357600080fd5b6001600160401b038216600090815260028501602090815260408083206003880190925282208291908280806139da85612624565b600886015490915060006139f66139ef875490565b879061305b565b90505b8051600090613a09908890613f45565b90508a6001600160a01b031682606001516001600160a01b03161415613b6157600080613a4a84604001518560200151600f0b612dd290919063ffffffff16565b905060048a5460ff166004811115613a6457613a64615315565b14158015613a725750600085115b8015613a88575085600f0b8460200151600f0b12155b15613b24576000613aa9856040015188600f0b612dd290919063ffffffff16565b90508585604001511115613ae457613ac5600f88900b87612dd2565b9050613ad18689615890565b9750613add8684615890565b9250613b08565b6040850151613af39089615890565b9750846040015183613b059190615890565b92505b613b12818361573e565b613b1c908a615890565b985050613b31565b613b2e8189615890565b97505b8e613b5e57818a6008016000828254613b4a919061573e565b90915550508351613b5c908a906130b4565b505b50505b8215613b8e578282604001511115613b7c5760009250613b8e565b6040820151613b8b908461573e565b92505b613b98878261305b565b8051909250151590506139f95750929b919a509098505050505050505050565b6001600160401b0380831660009081526002850160205260408120805491928392610100810490911690600160481b9004600f0b42821115613c035760008094509450505050613da0565b60405163098df99d60e11b81526001600160401b03831660048201526000907f000000000000000000000000e5dbc4edf467b609a063c7ea7fab976c6b9baa1a6001600160a01b03169063131bf33a90602401602060405180830381865afa158015613c73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c979190615784565b905060007f00000000000000000000000000000000000000000000000000000000000000008015613ccd575082600f0b82600f0b135b15613cf857613cf1886116a784613ce8600f82900b886138e7565b600f0b9061394d565b9050613d95565b7f0000000000000000000000000000000000000000000000000000000000000000158015613d2b575081600f0b83600f0b135b15613d95576000613d44896116a7600f87900b866138e7565b9050613d917f00000000000000000000000000000000000000000000000000000000000000127f00000000000000000000000000000000000000000000000000000000000000128361463c565b9150505b600196509450505050505b935093915050565b600081613db457600080fd5b6000613dc08484614659565b905060016001607f1b036001600160801b038216111561125357600080fd5b6001600160401b038116600090815260038301602090815260408083206002860190925282206006810154613e3f576000613e19826147bb565b905060008111613e3957613e2d8286612ca2565b600093505050506107b5565b60068201555b6000806000613e56613e4f865490565b869061305b565b90505b8051600090613e69908790613f45565b9050613e7485612624565b600f0b8260200151600f0b1215613e8b5750613f12565b60068501546040830151613e9f9086615890565b10613ee15750602001516002840180546001600160801b0319166001600160801b039092169190911790555050600681015460079091015550600190506107b5565b6040820151613ef09085615890565b60208301519094509250613f04868261305b565b805190925015159050613e59575b506002830180546001600160801b0319166001600160801b03929092169190911790556007909101555060009392505050565b600081815260038301602052604081208054613f655760009150506107b5565b613f6d614ebd565b60068201541561409a5750600680820154600090815260038087016020908152604092839020835161012081018552815460a082019081526001830154600f0b60c0830152600283015460e0830152938201546001600160a01b03166101008201529283526004810154918301919091526005810154928201929092529181015460608301526007015460808201525b60408101511561408f5760409081015160009081526003808701602090815291839020835161012081018552815460a082019081526001830154600f0b60c0830152600283015460e0830152928201546001600160a01b031661010082015291825260048101549282019290925260058201549281019290925260068101546060830152600701546080820152613ffd565b515191506107b59050565b6004820154156141d357506004810154600081815260038087016020908152604092839020835161012081018552865460a082019081526001880154600f0b60c0830152600288015460e0830152938701546001600160a01b0316610100820152928352908201939093526005840154918101919091526006830154606082015260078301546080820152905b81515160058201541415614140575492506107b5915050565b600481015461414e576141d1565b6040805161012081018252825460a082019081526001840154600f0b60c0830152600284015460e08301526003808501546001600160a01b03166101008401529082526004840154602080840182905260058601548486015260068601546060850152600790950154608084015260009081529089019093529120909150614127565b505b506000949350505050565b6000818152600383016020526040812080546141fe5760009150506107b5565b614206614ebd565b60058201541561432e5750600580820154600090815260038087016020908152604092839020835161012081018552815460a082019081526001830154600f0b60c0830152600283015460e0830152938201546001600160a01b031661010082015292835260048101549183019190915292830154918101919091526006820154606082015260079091015460808201525b60608101511561408f57606090810151600090815260038087016020908152604092839020835161012081018552815460a082019081526001830154600f0b60c0830152600283015460e0830152938201546001600160a01b0316610100820152928352600481015491830191909152600581015492820192909252600682015492810192909252600701546080820152614298565b6004820154156141d357506004810154600081815260038087016020908152604092839020835161012081018552865460a082019081526001880154600f0b60c0830152600288015460e0830152938701546001600160a01b0316610100820152928352908201939093526005840154918101919091526006830154606082015260078301546080820152905b815151600682015414156143d4575492506107b5915050565b60048101546143e2576141d1565b6040805161012081018252825460a082019081526001840154600f0b60c0830152600284015460e08301526003808501546001600160a01b031661010084015290825260048401546020808401829052600586015484860152600686015460608501526007909501546080840152600090815290890190935291209091506143bb565b600081815260038301602052604090205b805460009061448690859061493c565b905080600214156144c35761449f84836005015461493c565b60001914156144b6576144b6848360050154614974565b81546144c3908590614a68565b8060011914156144fe576144db84836006015461493c565b600114156144f1576144f1848360060154614a68565b81546144fe908590614974565b8060001913158015614511575060018113155b15614523578154614523908590614b4b565b60048201546145325750505050565b506004015460009081526003830160205260409020614476565b60006112538383614b9a565b815460009082106145b65760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b60648201526084016107ec565b8260000182815481106145cb576145cb6158a8565b9060005260206000200154905092915050565b6060610c178484600085614c67565b6000818152600183016020526040812054614634575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556107b5565b5060006107b5565b6000806146498386614d67565b90506127a0600f82900b85614d7d565b60008161466557600080fd5b60006001600160c01b0384116146905782604085901b81614688576146886159b8565b0490506147a7565b60c084811c64010000000081106146a9576020918201911c5b6201000081106146bb576010918201911c5b61010081106146cc576008918201911c5b601081106146dc576004918201911c5b600481106146ec576002918201911c5b600281106146fb576001820191505b60bf820360018603901c6001018260ff0387901b8161471c5761471c6159b8565b0492506001600160801b0383111561473357600080fd5b608085901c83026001600160801b038616840260c088901c604089901b8281101561475f576001820391505b608084901b92900382811015614776576001820391505b829003608084901c821461478c5761478c6159ce565b88818161479b5761479b6159b8565b04870196505050505050505b6001600160801b0381111561125357600080fd5b6000807f00000000000000000000000082900b0495303216d128d4770de425e0a3c14c1f6001600160a01b0316634ac8eb5f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561481c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614840919061597d565b905060007f00000000000000000000000082900b0495303216d128d4770de425e0a3c14c1f6001600160a01b031663a19471196040518163ffffffff1660e01b8152600401602060405180830381865afa1580156148a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148c6919061597d565b90508082116148d6576000610c17565b8354610c17907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000001290600160481b9004600f0b614934858761573e565b929190614d98565b6000818152600383016020526040808220600681015483528183206007908101546005830154855292842001549091610c17916159e4565b60008181526003830160205260409020600681015461499257600080fd5b6006810180546000908152600385016020526040812060048085015490820181905591909255156149fe576004820154600090815260038501602052604090208254600582015414156149e757815460058201555b8254600682015414156149fc57815460068201555b505b600581015415614a2d576005810154600090815260038501602052604090208054600684015582546004909101555b805460048084019190915582546005830155810154614a4e57805460028501555b8154614a5b908590614b4b565b805461145c908590614b4b565b600081815260038301602052604090206005810154614a8657600080fd5b600581018054600090815260038501602052604081206004808501549082018190559190925515614af257600482015460009081526003850160205260409020825460058201541415614adb57815460058201555b825460068201541415614af057815460068201555b505b600681015415614b2257600681015460008181526003860160205260409020600584019190915582546004909101555b805460048084019190915582546006830155810154614a4e57805460028501558154614a5b9085905b600081815260038301602052604080822060058101548352818320600790810154600683015485529290932090920154614b859190614dee565b614b90906001615890565b6007909101555050565b60008181526001830160205260408120548015614c5d57835460009085906000198101908110614bcc57614bcc6158a8565b9060005260206000200154905080856000016001840381548110614bf257614bf26158a8565b6000918252602080832090910192909255918252600186019052604090208190558354849080614c2457614c24615a23565b600190038181906000526020600020016000905590558360010160008481526020019081526020016000206000905560019150506107b5565b60009150506107b5565b6060843b614ccb5760405162461bcd60e51b815260206004820152602b60248201527f416464726573735574696c733a2066756e6374696f6e2063616c6c20746f206e60448201526a1bdb8b58dbdb9d1c9858dd60aa1b60648201526084016107ec565b600080866001600160a01b03168587604051614ce79190615a39565b60006040518083038185875af1925050503d8060008114614d24576040519150601f19603f3d011682016040523d82523d6000602084013e614d29565b606091505b50915091508115614d3d579150610c179050565b805115614d4d5780518082602001fd5b8360405162461bcd60e51b81526004016107ec9190615846565b600061125383614d7884600a615b39565b613da8565b6000611253614d8d83600a615b39565b600f85900b90612dd2565b600081600f0b60001415614dae57506000610c17565b8315614dbb575083610c17565b6000614dc78685614d67565b9050614de484614ddb600f84900b8661394d565b600f0b90614d7d565b9695505050505050565b6000818310614dfe5750816107b5565b50919050565b6040518060800160405280600081526020016000600f0b81526020016000815260200160006001600160a01b031681525090565b604080516101c08101909152806000815260200160006001600160401b031681526020016000600f0b81526020016000600f0b81526020016000600f0b81526020016000600f0b815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060a00160405280614ed0614e04565b8152602001600081526020016000815260200160008152602001600081525090565b600060208284031215614f0457600080fd5b81356001600160e01b03198116811461125357600080fd5b80356001600160401b0381168114614f3357600080fd5b919050565b600080600060608486031215614f4d57600080fd5b614f5684614f1c565b95602085013595506040909401359392505050565b600060208284031215614f7d57600080fd5b61125382614f1c565b80356001600160a01b0381168114614f3357600080fd5b600060208284031215614faf57600080fd5b61125382614f86565b80600f0b8114611f0657600080fd5b600060208284031215614fd957600080fd5b813561125381614fb8565b600060e08284031215614dfe57600080fd5b6000806000806080858703121561500c57600080fd5b84356001600160401b0381111561502257600080fd5b61502e87828801614fe4565b94505061503d60208601614f1c565b9250604085013561504d81614fb8565b9396929550929360600135925050565b6000806000806080858703121561507357600080fd5b84356001600160401b0381111561508957600080fd5b61509587828801614fe4565b9450506150a460208601614f1c565b93969395505050506040820135916060013590565b600080604083850312156150cc57600080fd5b6150d583614f1c565b915060208301356001600160801b03811681146150f157600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b0381118282101715615137576151376150fc565b6040525050565b600060c0828403121561515057600080fd5b60405160c081018181106001600160401b0382111715615172576151726150fc565b60405261517e83614f1c565b815261518c60208401614f1c565b6020820152604083013561519f81614fb8565b80604083015250606083013560608201526080830135608082015260a083013560a08201528091505092915050565b600080602083850312156151e157600080fd5b82356001600160401b03808211156151f857600080fd5b818501915085601f83011261520c57600080fd5b81358181111561521b57600080fd5b8660208260051b850101111561523057600080fd5b60209290920196919550909350505050565b60005b8381101561525d578181015183820152602001615245565b8381111561145c5750506000910152565b60008151808452615286816020860160208601615242565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156152ef57603f198886030184526152dd85835161526e565b945092850192908501906001016152c1565b5092979650505050505050565b60006020828403121561530e57600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b6005811061534957634e487b7160e01b600052602160045260246000fd5b9052565b602081016107b5828461532b565b60006101c08201905061536f82845161532b565b602083015161538960208401826001600160401b03169052565b50604083015161539e6040840182600f0b9052565b5060608301516153b36060840182600f0b9052565b5060808301516153c86080840182600f0b9052565b5060a08301516153dd60a0840182600f0b9052565b5060c0838101519083015260e08084015190830152610100808401519083015261012080840151908301526101408084015190830152610160808401519083015261018080840151908301526101a092830151929091019190915290565b600082601f83011261544c57600080fd5b813560206001600160401b03821115615467576154676150fc565b8160051b60405161547a83830182615112565b9283528481018201928281018785111561549357600080fd5b83870192505b848310156154b05782358152918301918301615499565b509695505050505050565b600082601f8301126154cc57600080fd5b81356001600160401b038111156154e5576154e56150fc565b6040516154fc601f8301601f191660200182615112565b81815284602083860101111561551157600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a0868803121561554657600080fd5b61554f86614f86565b945061555d60208701614f86565b935060408601356001600160401b038082111561557957600080fd5b61558589838a0161543b565b9450606088013591508082111561559b57600080fd5b6155a789838a0161543b565b935060808801359150808211156155bd57600080fd5b506155ca888289016154bb565b9150509295509295909350565b6000806000606084860312156155ec57600080fd5b6155f584614f1c565b9250602084013561560581614fb8565b929592945050506040919091013590565b6000806040838503121561562957600080fd5b61563283614f1c565b915061564060208401614f86565b90509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561568157835183529284019291840191600101615665565b50909695505050505050565b600080600080600060a086880312156156a557600080fd5b6156ae86614f86565b94506156bc60208701614f86565b9350604086013592506060860135915060808601356001600160401b038111156156e557600080fd5b6155ca888289016154bb565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008282101561575057615750615728565b500390565b6020808252601590820152741cdd185d1d5cc8084f481a5b9a5d1a585b1a5e9959605a1b604082015260600190565b60006020828403121561579657600080fd5b815161125381614fb8565b600060033d11156157ba5760046000803e5060005160e01c5b90565b600060443d10156157cb5790565b6040516003193d81016004833e81513d6001600160401b0381602484011181841117156157fa57505050505090565b82850191508151818111156158125750505050505090565b843d870101602082850101111561582c5750505050505090565b61583b60208286010187615112565b509095945050505050565b602081526000611253602083018461526e565b6020808252601d908201527f4f776e61626c653a2073656e646572206d757374206265206f776e6572000000604082015260600190565b600082198211156158a3576158a3615728565b500190565b634e487b7160e01b600052603260045260246000fd5b6000808335601e198436030181126158d557600080fd5b8301803591506001600160401b038211156158ef57600080fd5b602001915036819003821315611dce57600080fd5b8183823760009101908152919050565b600060018060a01b03808b168352808a1660208401528860408401528088166060840152808716608084015260e060a08401528460e08401526101008587828601376000848701820152931660c083015250601f909201601f1916909101019695505050505050565b60006020828403121561598f57600080fd5b5051919050565b6000602082840312156159a857600080fd5b8151801515811461125357600080fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b60008083128015600160ff1b850184121615615a0257615a02615728565b6001600160ff1b0384018313811615615a1d57615a1d615728565b50500390565b634e487b7160e01b600052603160045260246000fd5b60008251615a4b818460208701615242565b9190910192915050565b600181815b80851115615a90578160001904821115615a7657615a76615728565b80851615615a8357918102915b93841c9390800290615a5a565b509250929050565b600082615aa7575060016107b5565b81615ab4575060006107b5565b8160018114615aca5760028114615ad457615af0565b60019150506107b5565b60ff841115615ae557615ae5615728565b50506001821b6107b5565b5060208310610133831016604e8410600b8410161715615b13575081810a6107b5565b615b1d8383615a55565b8060001904821115615b3157615b31615728565b029392505050565b600061125360ff841683615a9856fe8a22373512790c48b83a1fe2efdd2888d4a917bcdc24d0adf63e60f67168046009acf4e54214992e70883cf7dcd6957ff2c71cd9e14df4bec4383bc0d11607dca264697066735822122071520f7a01fd7d370bd739d9cd965a8238fb4730007d5c800318f6424844443c64736f6c634300080c0033

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

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e5dbc4edf467b609a063c7ea7fab976c6b9baa1a00000000000000000000000082900b0495303216d128d4770de425e0a3c14c1f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1

-----Decoded View---------------
Arg [0] : isCall (bool): False
Arg [1] : pool (address): 0xE5DbC4EDf467B609A063c7ea7fAb976C6b9BAa1a
Arg [2] : vault (address): 0x82900b0495303216d128d4770de425E0a3c14C1f
Arg [3] : weth (address): 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [1] : 000000000000000000000000e5dbc4edf467b609a063c7ea7fab976c6b9baa1a
Arg [2] : 00000000000000000000000082900b0495303216d128d4770de425e0a3c14c1f
Arg [3] : 00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.