ETH Price: $3,358.62 (-8.27%)
 
Transaction Hash
Method
Block
From
To
Execute154943832022-09-08 3:58:11853 days ago1662609491IN
Integral: Delay
0 ETH0.0032799313.39497784
Withdraw154942502022-09-08 3:28:00853 days ago1662607680IN
Integral: Delay
0.02142 ETH0.0027669116.06571125
Execute154793872022-09-05 18:26:45855 days ago1662402405IN
Integral: Delay
0 ETH0.0029117212.22770628
Withdraw154792422022-09-05 17:56:30855 days ago1662400590IN
Integral: Delay
0.00916062 ETH0.0018666410.83836594
Execute154442472022-08-31 3:24:30861 days ago1661916270IN
Integral: Delay
0 ETH0.0041048516.27780301
Withdraw154441212022-08-31 2:53:52861 days ago1661914432IN
Integral: Delay
0.0091938 ETH0.0026097615.15419158
Execute154395972022-08-30 9:27:01862 days ago1661851621IN
Integral: Delay
0 ETH0.003147210.55733724
Withdraw154394642022-08-30 8:56:46862 days ago1661849806IN
Integral: Delay
0.01112882 ETH0.001301937.56
Execute154384742022-08-30 5:15:28862 days ago1661836528IN
Integral: Delay
0 ETH0.0045845111.64206997
Withdraw154383352022-08-30 4:43:57862 days ago1661834637IN
Integral: Delay
0.00935886 ETH0.001293247.50900565
Execute153784672022-08-20 15:47:30871 days ago1661010450IN
Integral: Delay
0 ETH0.0039278814.59582786
Withdraw153783532022-08-20 15:16:56871 days ago1661008616IN
Integral: Delay
0.009408 ETH0.0019275911.19377447
Execute153619462022-08-18 0:49:03874 days ago1660783743IN
Integral: Delay
0 ETH0.002519739.36320624
Execute153619412022-08-18 0:47:58874 days ago1660783678IN
Integral: Delay
0 ETH0.0003451910
Withdraw153618122022-08-18 0:18:09874 days ago1660781889IN
Integral: Delay
0.00949158 ETH0.001338077.77089426
Execute153434052022-08-15 2:24:02877 days ago1660530242IN
Integral: Delay
0 ETH0.013328133.84580738
Withdraw153432802022-08-15 1:53:04877 days ago1660528384IN
Integral: Delay
0.00940044 ETH0.001630949.4698138
Execute153376572022-08-14 4:40:23878 days ago1660452023IN
Integral: Delay
0 ETH0.003433548.71926033
Execute153376542022-08-14 4:39:18878 days ago1660451958IN
Integral: Delay
0 ETH0.000310679
Withdraw153375372022-08-14 4:09:26878 days ago1660450166IN
Integral: Delay
0.00951132 ETH0.001462828.49362211
Execute153374702022-08-14 3:56:00878 days ago1660449360IN
Integral: Delay
0 ETH0.0135356934.37295826
Execute153374662022-08-14 3:54:57878 days ago1660449297IN
Integral: Delay
0 ETH0.0014152741
Withdraw153373342022-08-14 3:25:09878 days ago1660447509IN
Integral: Delay
0.0094164 ETH0.001223437.10365058
Execute153371852022-08-14 2:50:34878 days ago1660445434IN
Integral: Delay
0 ETH0.001656426.5782029
Withdraw153370562022-08-14 2:19:37878 days ago1660443577IN
Integral: Delay
0.00951048 ETH0.00191211.10169988
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
154943832022-09-08 3:58:11853 days ago1662609491
Integral: Delay
0.00359354 ETH
154943832022-09-08 3:58:11853 days ago1662609491
Integral: Delay
0.00508085 ETH
154942502022-09-08 3:28:00853 days ago1662607680
Integral: Delay
0.0127456 ETH
154793872022-09-05 18:26:45855 days ago1662402405
Integral: Delay
0.00340066 ETH
154793872022-09-05 18:26:45855 days ago1662402405
Integral: Delay
0.00532373 ETH
154793872022-09-05 18:26:45855 days ago1662402405
Integral: Delay
12.52682638 ETH
154793872022-09-05 18:26:45855 days ago1662402405
Integral: Delay
12.52682638 ETH
154792422022-09-05 17:56:30855 days ago1662400590
Integral: Delay
0.00043622 ETH
154442472022-08-31 3:24:30861 days ago1661916270
Integral: Delay
0.00302854 ETH
154442472022-08-31 3:24:30861 days ago1661916270
Integral: Delay
0.00572745 ETH
154442472022-08-31 3:24:30861 days ago1661916270
Integral: Delay
0.0537528 ETH
154442472022-08-31 3:24:30861 days ago1661916270
Integral: Delay
0.0537528 ETH
154441212022-08-31 2:53:52861 days ago1661914432
Integral: Delay
0.0004378 ETH
154395972022-08-30 9:27:01862 days ago1661851621
Integral: Delay
0.00364921 ETH
154395972022-08-30 9:27:01862 days ago1661851621
Integral: Delay
0.00694966 ETH
154395972022-08-30 9:27:01862 days ago1661851621
Integral: Delay
59.92119471 ETH
154395972022-08-30 9:27:01862 days ago1661851621
Integral: Delay
59.92119471 ETH
154394642022-08-30 8:56:46862 days ago1661849806
Integral: Delay
0.00052994 ETH
154384742022-08-30 5:15:28862 days ago1661836528
Integral: Delay
0.00094239 ETH
154384742022-08-30 5:15:28862 days ago1661836528
Integral: Delay
0.0079708 ETH
154384742022-08-30 5:15:28862 days ago1661836528
Integral: Delay
59.92119471 ETH
154383352022-08-30 4:43:57862 days ago1661834637
Integral: Delay
0.00044566 ETH
153784672022-08-20 15:47:30871 days ago1661010450
Integral: Delay
0.00262492 ETH
153784672022-08-20 15:47:30871 days ago1661010450
Integral: Delay
0.00633507 ETH
153784672022-08-20 15:47:30871 days ago1661010450
Integral: Delay
9.6226839 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
TwapDelay

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 25 : TwapDelay.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;
pragma abicoder v2;

import './interfaces/ITwapPair.sol';
import './interfaces/ITwapDelay.sol';
import './interfaces/IWETH.sol';
import './libraries/SafeMath.sol';
import './libraries/Orders.sol';
import './libraries/TokenShares.sol';
import './libraries/AddLiquidity.sol';
import './libraries/WithdrawHelper.sol';

contract TwapDelay is ITwapDelay {
    using SafeMath for uint256;
    using Orders for Orders.Data;
    using TokenShares for TokenShares.Data;
    Orders.Data internal orders;
    TokenShares.Data internal tokenShares;

    uint256 private constant ORDER_CANCEL_TIME = 24 hours;
    uint256 private constant BOT_EXECUTION_TIME = 20 minutes;
    uint256 private constant ORDER_LIFESPAN = 48 hours;

    address public override owner;
    mapping(address => bool) public override isBot;

    constructor(
        address _factory,
        address _weth,
        address _bot
    ) {
        orders.factory = _factory;
        owner = msg.sender;
        isBot[_bot] = true;
        orders.gasPrice = tx.gasprice - (tx.gasprice % 1e6);
        tokenShares.setWeth(_weth);
        orders.delay = 30 minutes;
        orders.maxGasLimit = 5_000_000;
        orders.gasPriceInertia = 20_000_000;
        orders.maxGasPriceImpact = 1_000_000;
        orders.setTransferGasCost(address(0), Orders.ETHER_TRANSFER_CALL_COST);

        emit OwnerSet(msg.sender);
    }

    function getTransferGasCost(address token) external view override returns (uint256 gasCost) {
        return orders.transferGasCosts[token];
    }

    function getDepositOrder(uint256 orderId) external view override returns (Orders.DepositOrder memory order) {
        return orders.getDepositOrder(orderId);
    }

    function getWithdrawOrder(uint256 orderId) external view override returns (Orders.WithdrawOrder memory order) {
        return orders.getWithdrawOrder(orderId);
    }

    function getSellOrder(uint256 orderId) external view override returns (Orders.SellOrder memory order) {
        return orders.getSellOrder(orderId);
    }

    function getBuyOrder(uint256 orderId) external view override returns (Orders.BuyOrder memory order) {
        return orders.getBuyOrder(orderId);
    }

    function getDepositDisabled(address pair) external view override returns (bool) {
        return orders.getDepositDisabled(pair);
    }

    function getWithdrawDisabled(address pair) external view override returns (bool) {
        return orders.getWithdrawDisabled(pair);
    }

    function getBuyDisabled(address pair) external view override returns (bool) {
        return orders.getBuyDisabled(pair);
    }

    function getSellDisabled(address pair) external view override returns (bool) {
        return orders.getSellDisabled(pair);
    }

    function getOrderStatus(uint256 orderId) external view override returns (Orders.OrderStatus) {
        return orders.getOrderStatus(orderId);
    }

    uint256 private unlocked = 1;
    modifier lock() {
        require(unlocked == 1, 'TD06');
        unlocked = 0;
        _;
        unlocked = 1;
    }

    function factory() external view override returns (address) {
        return orders.factory;
    }

    function totalShares(address token) external view override returns (uint256) {
        return tokenShares.totalShares[token];
    }

    function weth() external view override returns (address) {
        return tokenShares.weth;
    }

    function delay() external view override returns (uint32) {
        return orders.delay;
    }

    function lastProcessedOrderId() external view returns (uint256) {
        return orders.lastProcessedOrderId;
    }

    function newestOrderId() external view returns (uint256) {
        return orders.newestOrderId;
    }

    function getOrder(uint256 orderId) external view returns (Orders.OrderType orderType, uint32 validAfterTimestamp) {
        return orders.getOrder(orderId);
    }

    function isOrderCanceled(uint256 orderId) external view returns (bool) {
        return orders.canceled[orderId];
    }

    function maxGasLimit() external view override returns (uint256) {
        return orders.maxGasLimit;
    }

    function maxGasPriceImpact() external view override returns (uint256) {
        return orders.maxGasPriceImpact;
    }

    function gasPriceInertia() external view override returns (uint256) {
        return orders.gasPriceInertia;
    }

    function gasPrice() external view override returns (uint256) {
        return orders.gasPrice;
    }

    function setOrderDisabled(
        address pair,
        Orders.OrderType orderType,
        bool disabled
    ) external override {
        require(msg.sender == owner, 'TD00');
        orders.setOrderDisabled(pair, orderType, disabled);
    }

    function setOwner(address _owner) external override {
        require(msg.sender == owner, 'TD00');
        require(_owner != owner, 'TD01');
        require(_owner != address(0), 'TD02');
        owner = _owner;
        emit OwnerSet(_owner);
    }

    function setBot(address _bot, bool _isBot) external override {
        require(msg.sender == owner, 'TD00');
        require(_isBot != isBot[_bot], 'TD01');
        isBot[_bot] = _isBot;
        emit BotSet(_bot, _isBot);
    }

    function setMaxGasLimit(uint256 _maxGasLimit) external override {
        require(msg.sender == owner, 'TD00');
        orders.setMaxGasLimit(_maxGasLimit);
    }

    function setDelay(uint32 _delay) external override {
        require(msg.sender == owner, 'TD00');
        require(_delay != orders.delay, 'TD01');
        orders.delay = _delay;
        emit DelaySet(_delay);
    }

    function setGasPriceInertia(uint256 _gasPriceInertia) external override {
        require(msg.sender == owner, 'TD00');
        orders.setGasPriceInertia(_gasPriceInertia);
    }

    function setMaxGasPriceImpact(uint256 _maxGasPriceImpact) external override {
        require(msg.sender == owner, 'TD00');
        orders.setMaxGasPriceImpact(_maxGasPriceImpact);
    }

    function setTransferGasCost(address token, uint256 gasCost) external override {
        require(msg.sender == owner, 'TD00');
        orders.setTransferGasCost(token, gasCost);
    }

    function deposit(Orders.DepositParams calldata depositParams)
        external
        payable
        override
        lock
        returns (uint256 orderId)
    {
        orders.deposit(depositParams, tokenShares);
        return orders.newestOrderId;
    }

    function withdraw(Orders.WithdrawParams calldata withdrawParams)
        external
        payable
        override
        lock
        returns (uint256 orderId)
    {
        orders.withdraw(withdrawParams);
        return orders.newestOrderId;
    }

    function sell(Orders.SellParams calldata sellParams) external payable override lock returns (uint256 orderId) {
        orders.sell(sellParams, tokenShares);
        return orders.newestOrderId;
    }

    function buy(Orders.BuyParams calldata buyParams) external payable override lock returns (uint256 orderId) {
        orders.buy(buyParams, tokenShares);
        return orders.newestOrderId;
    }

    function execute(uint256 n) external override lock {
        emit Execute(msg.sender, n);
        uint256 gasBefore = gasleft();
        bool orderExecuted = false;
        bool senderCanExecute = isBot[msg.sender] || isBot[address(0)];
        for (uint256 i = 0; i < n; i++) {
            if (orders.canceled[orders.lastProcessedOrderId + 1]) {
                orders.dequeueCanceledOrder();
                continue;
            }
            (Orders.OrderType orderType, uint256 validAfterTimestamp) = orders.getNextOrder();
            if (orderType == Orders.OrderType.Empty || validAfterTimestamp >= block.timestamp) {
                break;
            }
            require(senderCanExecute || block.timestamp >= validAfterTimestamp + BOT_EXECUTION_TIME, 'TD00');
            orderExecuted = true;
            if (orderType == Orders.OrderType.Deposit) {
                executeDeposit();
            } else if (orderType == Orders.OrderType.Withdraw) {
                executeWithdraw();
            } else if (orderType == Orders.OrderType.Sell) {
                executeSell();
            } else if (orderType == Orders.OrderType.Buy) {
                executeBuy();
            }
        }
        if (orderExecuted) {
            orders.updateGasPrice(gasBefore.sub(gasleft()));
        }
    }

    function executeDeposit() internal {
        uint256 gasStart = gasleft();
        Orders.DepositOrder memory depositOrder = orders.dequeueDepositOrder();
        (, address token0, address token1) = orders.getPairInfo(depositOrder.pairId);
        (bool executionSuccess, bytes memory data) = address(this).call{
            gas: depositOrder.gasLimit.sub(
                Orders.ORDER_BASE_COST.add(orders.transferGasCosts[token0]).add(orders.transferGasCosts[token1])
            )
        }(abi.encodeWithSelector(this._executeDeposit.selector, depositOrder));
        bool refundSuccess = true;
        if (!executionSuccess) {
            refundSuccess = refundTokens(
                depositOrder.to,
                token0,
                depositOrder.share0,
                token1,
                depositOrder.share1,
                depositOrder.unwrap
            );
        }
        finalizeOrder(refundSuccess);
        (uint256 gasUsed, uint256 ethRefund) = refund(
            depositOrder.gasLimit,
            depositOrder.gasPrice,
            gasStart,
            depositOrder.to
        );
        emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund);
    }

    function executeWithdraw() internal {
        uint256 gasStart = gasleft();
        Orders.WithdrawOrder memory withdrawOrder = orders.dequeueWithdrawOrder();
        (bool executionSuccess, bytes memory data) = address(this).call{
            gas: withdrawOrder.gasLimit.sub(Orders.ORDER_BASE_COST.add(Orders.PAIR_TRANSFER_COST))
        }(abi.encodeWithSelector(this._executeWithdraw.selector, withdrawOrder));
        bool refundSuccess = true;
        if (!executionSuccess) {
            (address pair, , ) = orders.getPairInfo(withdrawOrder.pairId);
            refundSuccess = refundLiquidity(pair, withdrawOrder.to, withdrawOrder.liquidity);
        }
        finalizeOrder(refundSuccess);
        (uint256 gasUsed, uint256 ethRefund) = refund(
            withdrawOrder.gasLimit,
            withdrawOrder.gasPrice,
            gasStart,
            withdrawOrder.to
        );
        emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund);
    }

    function executeSell() internal {
        uint256 gasStart = gasleft();
        Orders.SellOrder memory sellOrder = orders.dequeueSellOrder();
        (, address token0, address token1) = orders.getPairInfo(sellOrder.pairId);
        (bool executionSuccess, bytes memory data) = address(this).call{
            gas: sellOrder.gasLimit.sub(
                Orders.ORDER_BASE_COST.add(orders.transferGasCosts[sellOrder.inverse ? token1 : token0])
            )
        }(abi.encodeWithSelector(this._executeSell.selector, sellOrder));
        bool refundSuccess = true;
        if (!executionSuccess) {
            refundSuccess = refundToken(
                sellOrder.inverse ? token1 : token0,
                sellOrder.to,
                sellOrder.shareIn,
                sellOrder.unwrap
            );
        }
        finalizeOrder(refundSuccess);
        (uint256 gasUsed, uint256 ethRefund) = refund(sellOrder.gasLimit, sellOrder.gasPrice, gasStart, sellOrder.to);
        emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund);
    }

    function executeBuy() internal {
        uint256 gasStart = gasleft();
        Orders.BuyOrder memory buyOrder = orders.dequeueBuyOrder();
        (, address token0, address token1) = orders.getPairInfo(buyOrder.pairId);
        (bool executionSuccess, bytes memory data) = address(this).call{
            gas: buyOrder.gasLimit.sub(
                Orders.ORDER_BASE_COST.add(orders.transferGasCosts[buyOrder.inverse ? token1 : token0])
            )
        }(abi.encodeWithSelector(this._executeBuy.selector, buyOrder));
        bool refundSuccess = true;
        if (!executionSuccess) {
            refundSuccess = refundToken(
                buyOrder.inverse ? token1 : token0,
                buyOrder.to,
                buyOrder.shareInMax,
                buyOrder.unwrap
            );
        }
        finalizeOrder(refundSuccess);
        (uint256 gasUsed, uint256 ethRefund) = refund(buyOrder.gasLimit, buyOrder.gasPrice, gasStart, buyOrder.to);
        emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund);
    }

    function finalizeOrder(bool refundSuccess) private {
        if (!refundSuccess) {
            orders.markRefundFailed();
        } else {
            orders.forgetLastProcessedOrder();
        }
    }

    function refund(
        uint256 gasLimit,
        uint256 gasPriceInOrder,
        uint256 gasStart,
        address to
    ) private returns (uint256 gasUsed, uint256 leftOver) {
        uint256 feeCollected = gasLimit.mul(gasPriceInOrder);
        gasUsed = gasStart.sub(gasleft()).add(Orders.REFUND_BASE_COST);
        uint256 actualRefund = Math.min(feeCollected, gasUsed.mul(orders.gasPrice));
        leftOver = feeCollected.sub(actualRefund);
        require(refundEth(msg.sender, actualRefund), 'TD40');
        refundEth(payable(to), leftOver);
    }

    function refundEth(address payable to, uint256 value) internal returns (bool success) {
        if (value == 0) {
            return true;
        }
        success = TransferHelper.transferETH(to, value, orders.transferGasCosts[address(0)]);
        emit EthRefund(to, success, value);
    }

    function refundToken(
        address token,
        address to,
        uint256 share,
        bool unwrap
    ) private returns (bool) {
        if (share == 0) {
            return true;
        }
        (bool success, bytes memory data) = address(this).call{ gas: orders.transferGasCosts[token] }(
            abi.encodeWithSelector(this._refundToken.selector, token, to, share, unwrap)
        );
        if (!success) {
            emit RefundFailed(to, token, share, data);
        }
        return success;
    }

    function refundTokens(
        address to,
        address token0,
        uint256 share0,
        address token1,
        uint256 share1,
        bool unwrap
    ) private returns (bool) {
        (bool success, bytes memory data) = address(this).call{
            gas: orders.transferGasCosts[token0].add(orders.transferGasCosts[token1])
        }(abi.encodeWithSelector(this._refundTokens.selector, to, token0, share0, token1, share1, unwrap));
        if (!success) {
            emit RefundFailed(to, token0, share0, data);
            emit RefundFailed(to, token1, share1, data);
        }
        return success;
    }

    function _refundTokens(
        address to,
        address token0,
        uint256 share0,
        address token1,
        uint256 share1,
        bool unwrap
    ) external {
        // no need to check sender, because it is checked in _refundToken
        _refundToken(token0, to, share0, unwrap);
        _refundToken(token1, to, share1, unwrap);
    }

    function _refundToken(
        address token,
        address to,
        uint256 share,
        bool unwrap
    ) public {
        require(msg.sender == address(this), 'TD00');
        if (token == tokenShares.weth && unwrap) {
            uint256 amount = tokenShares.sharesToAmount(token, share);
            IWETH(tokenShares.weth).withdraw(amount);
            TransferHelper.safeTransferETH(to, amount, orders.transferGasCosts[address(0)]);
        } else {
            TransferHelper.safeTransfer(token, to, tokenShares.sharesToAmount(token, share));
        }
    }

    function refundLiquidity(
        address pair,
        address to,
        uint256 liquidity
    ) private returns (bool) {
        if (liquidity == 0) {
            return true;
        }
        (bool success, bytes memory data) = address(this).call{ gas: Orders.PAIR_TRANSFER_COST }(
            abi.encodeWithSelector(this._refundLiquidity.selector, pair, to, liquidity, false)
        );
        if (!success) {
            emit RefundFailed(to, pair, liquidity, data);
        }
        return success;
    }

    function _refundLiquidity(
        address pair,
        address to,
        uint256 liquidity
    ) external {
        require(msg.sender == address(this), 'TD00');
        return TransferHelper.safeTransfer(pair, to, liquidity);
    }

    function _executeDeposit(Orders.DepositOrder memory depositOrder) external {
        require(msg.sender == address(this), 'TD00');
        require(depositOrder.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04');

        (address pair, address token0, address token1, uint256 amount0Left, uint256 amount1Left) = _initialDeposit(
            depositOrder
        );
        if (depositOrder.swap) {
            if (amount0Left != 0) {
                (amount0Left, amount1Left) = AddLiquidity.swapDeposit0(
                    pair,
                    token0,
                    amount0Left,
                    depositOrder.minSwapPrice,
                    encodePriceInfo(pair, depositOrder.priceAccumulator, depositOrder.timestamp)
                );
            } else if (amount1Left != 0) {
                (amount0Left, amount1Left) = AddLiquidity.swapDeposit1(
                    pair,
                    token1,
                    amount1Left,
                    depositOrder.maxSwapPrice,
                    encodePriceInfo(pair, depositOrder.priceAccumulator, depositOrder.timestamp)
                );
            }
        }
        if (amount0Left != 0 && amount1Left != 0) {
            (amount0Left, amount1Left) = AddLiquidity.addLiquidityAndMint(
                pair,
                depositOrder.to,
                token0,
                token1,
                amount0Left,
                amount1Left
            );
        }

        _refundDeposit(depositOrder.to, token0, token1, amount0Left, amount1Left);
    }

    function _initialDeposit(Orders.DepositOrder memory depositOrder)
        private
        returns (
            address pair,
            address token0,
            address token1,
            uint256 amount0Left,
            uint256 amount1Left
        )
    {
        (pair, token0, token1) = orders.getPairInfo(depositOrder.pairId);
        uint256 amount0Desired = tokenShares.sharesToAmount(token0, depositOrder.share0);
        uint256 amount1Desired = tokenShares.sharesToAmount(token1, depositOrder.share1);
        ITwapPair(pair).sync();
        (amount0Left, amount1Left) = AddLiquidity.addLiquidityAndMint(
            pair,
            depositOrder.to,
            token0,
            token1,
            amount0Desired,
            amount1Desired
        );
    }

    function _refundDeposit(
        address to,
        address token0,
        address token1,
        uint256 amount0,
        uint256 amount1
    ) private {
        if (amount0 > 0) {
            TransferHelper.safeTransfer(token0, to, amount0);
        }
        if (amount1 > 0) {
            TransferHelper.safeTransfer(token1, to, amount1);
        }
    }

    function _executeWithdraw(Orders.WithdrawOrder memory withdrawOrder) external {
        require(msg.sender == address(this), 'TD00');
        require(withdrawOrder.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04');

        (address pair, address token0, address token1) = orders.getPairInfo(withdrawOrder.pairId);
        ITwapPair(pair).sync();
        TransferHelper.safeTransfer(pair, pair, withdrawOrder.liquidity);

        (uint256 wethAmount, uint256 amount0, uint256 amount1) = (0, 0, 0);
        if (withdrawOrder.unwrap && (token0 == tokenShares.weth || token1 == tokenShares.weth)) {
            bool success;
            (success, wethAmount, amount0, amount1) = WithdrawHelper.withdrawAndUnwrap(
                token0,
                token1,
                pair,
                tokenShares.weth,
                withdrawOrder.to,
                orders.transferGasCosts[address(0)]
            );
            if (!success) {
                tokenShares.onUnwrapFailed(withdrawOrder.to, wethAmount);
            }
        } else {
            (amount0, amount1) = ITwapPair(pair).burn(withdrawOrder.to);
        }
        require(amount0 >= withdrawOrder.amount0Min && amount1 >= withdrawOrder.amount1Min, 'TD03');
    }

    function _executeBuy(Orders.BuyOrder memory buyOrder) external {
        require(msg.sender == address(this), 'TD00');
        require(buyOrder.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04');

        (address pairAddress, address tokenIn, address tokenOut) = _getPairAndTokens(buyOrder.pairId, buyOrder.inverse);
        uint256 amountInMax = tokenShares.sharesToAmount(tokenIn, buyOrder.shareInMax);
        ITwapPair pair = ITwapPair(pairAddress);
        pair.sync();
        bytes memory priceInfo = encodePriceInfo(pairAddress, buyOrder.priceAccumulator, buyOrder.timestamp);
        uint256 amountIn = buyOrder.inverse
            ? pair.getSwapAmount1In(buyOrder.amountOut, priceInfo)
            : pair.getSwapAmount0In(buyOrder.amountOut, priceInfo);
        require(amountInMax >= amountIn, 'TD08');
        if (amountInMax > amountIn) {
            if (tokenIn == tokenShares.weth && buyOrder.unwrap) {
                _forceEtherTransfer(buyOrder.to, amountInMax.sub(amountIn));
            } else {
                TransferHelper.safeTransfer(tokenIn, buyOrder.to, amountInMax.sub(amountIn));
            }
        }
        (uint256 amount0Out, uint256 amount1Out) = buyOrder.inverse
            ? (buyOrder.amountOut, uint256(0))
            : (uint256(0), buyOrder.amountOut);
        TransferHelper.safeTransfer(tokenIn, pairAddress, amountIn);
        if (tokenOut == tokenShares.weth && buyOrder.unwrap) {
            pair.swap(amount0Out, amount1Out, address(this), priceInfo);
            _forceEtherTransfer(buyOrder.to, buyOrder.amountOut);
        } else {
            pair.swap(amount0Out, amount1Out, buyOrder.to, priceInfo);
        }
    }

    function _executeSell(Orders.SellOrder memory sellOrder) external {
        require(msg.sender == address(this), 'TD00');
        require(sellOrder.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04');

        (address pairAddress, address tokenIn, address tokenOut) = _getPairAndTokens(
            sellOrder.pairId,
            sellOrder.inverse
        );
        uint256 amountIn = tokenShares.sharesToAmount(tokenIn, sellOrder.shareIn);
        ITwapPair pair = ITwapPair(pairAddress);
        pair.sync();
        bytes memory priceInfo = encodePriceInfo(pairAddress, sellOrder.priceAccumulator, sellOrder.timestamp);
        uint256 amountOut = sellOrder.inverse
            ? pair.getSwapAmount0Out(amountIn, priceInfo)
            : pair.getSwapAmount1Out(amountIn, priceInfo);
        require(amountOut >= sellOrder.amountOutMin, 'TD37');
        (uint256 amount0Out, uint256 amount1Out) = sellOrder.inverse
            ? (amountOut, uint256(0))
            : (uint256(0), amountOut);
        TransferHelper.safeTransfer(tokenIn, pairAddress, amountIn);
        if (tokenOut == tokenShares.weth && sellOrder.unwrap) {
            pair.swap(amount0Out, amount1Out, address(this), priceInfo);
            _forceEtherTransfer(sellOrder.to, amountOut);
        } else {
            pair.swap(amount0Out, amount1Out, sellOrder.to, priceInfo);
        }
    }

    function _getPairAndTokens(uint32 pairId, bool pairInversed)
        private
        view
        returns (
            address,
            address,
            address
        )
    {
        (address pairAddress, address token0, address token1) = orders.getPairInfo(pairId);
        (address tokenIn, address tokenOut) = pairInversed ? (token1, token0) : (token0, token1);
        return (pairAddress, tokenIn, tokenOut);
    }

    function _forceEtherTransfer(address to, uint256 amount) internal {
        IWETH(tokenShares.weth).withdraw(amount);
        (bool success, ) = to.call{ value: amount, gas: orders.transferGasCosts[address(0)] }('');
        if (!success) {
            tokenShares.onUnwrapFailed(to, amount);
        }
    }

    function performRefund(
        Orders.OrderType orderType,
        uint256 validAfterTimestamp,
        uint256 orderId,
        bool shouldRefundEth
    ) internal {
        require(orderType != Orders.OrderType.Empty, 'TD41');
        bool canOwnerRefund = validAfterTimestamp.add(365 days) < block.timestamp;

        if (orderType == Orders.OrderType.Deposit) {
            Orders.DepositOrder memory depositOrder = orders.getDepositOrder(orderId);
            (, address token0, address token1) = orders.getPairInfo(depositOrder.pairId);
            address to = canOwnerRefund ? owner : depositOrder.to;
            require(
                refundTokens(to, token0, depositOrder.share0, token1, depositOrder.share1, depositOrder.unwrap),
                'TD14'
            );
            if (shouldRefundEth) {
                uint256 value = depositOrder.gasPrice.mul(depositOrder.gasLimit);
                require(refundEth(payable(to), value), 'TD40');
            }
        } else if (orderType == Orders.OrderType.Withdraw) {
            Orders.WithdrawOrder memory withdrawOrder = orders.getWithdrawOrder(orderId);
            (address pair, , ) = orders.getPairInfo(withdrawOrder.pairId);
            address to = canOwnerRefund ? owner : withdrawOrder.to;
            require(refundLiquidity(pair, to, withdrawOrder.liquidity), 'TD14');
            if (shouldRefundEth) {
                uint256 value = withdrawOrder.gasPrice.mul(withdrawOrder.gasLimit);
                require(refundEth(payable(to), value), 'TD40');
            }
        } else if (orderType == Orders.OrderType.Sell) {
            Orders.SellOrder memory sellOrder = orders.getSellOrder(orderId);
            (, address token0, address token1) = orders.getPairInfo(sellOrder.pairId);
            address to = canOwnerRefund ? owner : sellOrder.to;
            require(refundToken(sellOrder.inverse ? token1 : token0, to, sellOrder.shareIn, sellOrder.unwrap), 'TD14');
            if (shouldRefundEth) {
                uint256 value = sellOrder.gasPrice.mul(sellOrder.gasLimit);
                require(refundEth(payable(to), value), 'TD40');
            }
        } else if (orderType == Orders.OrderType.Buy) {
            Orders.BuyOrder memory buyOrder = orders.getBuyOrder(orderId);
            (, address token0, address token1) = orders.getPairInfo(buyOrder.pairId);
            address to = canOwnerRefund ? owner : buyOrder.to;
            require(refundToken(buyOrder.inverse ? token1 : token0, to, buyOrder.shareInMax, buyOrder.unwrap), 'TD14');
            if (shouldRefundEth) {
                uint256 value = buyOrder.gasPrice.mul(buyOrder.gasLimit);
                require(refundEth(payable(to), value), 'TD40');
            }
        }
        orders.forgetOrder(orderId);
    }

    function retryRefund(uint256 orderId) external override lock {
        (Orders.OrderType orderType, uint256 validAfterTimestamp) = orders.getFailedOrderType(orderId);
        performRefund(orderType, validAfterTimestamp, orderId, false);
    }

    function cancelOrder(uint256 orderId) external override lock {
        require(orders.getOrderStatus(orderId) == Orders.OrderStatus.EnqueuedReady, 'TD52');
        (Orders.OrderType orderType, uint256 validAfterTimestamp) = orders.getOrder(orderId);
        require(validAfterTimestamp.sub(orders.delay).add(ORDER_CANCEL_TIME) < block.timestamp, 'TD1C');
        orders.canceled[orderId] = true;
        performRefund(orderType, validAfterTimestamp, orderId, true);
    }

    function encodePriceInfo(
        address pair,
        uint256 priceAccumulator,
        uint32 priceTimestamp
    ) internal view returns (bytes memory data) {
        uint256 price = ITwapOracle(ITwapPair(pair).oracle()).getAveragePrice(priceAccumulator, priceTimestamp);
        // Pack everything as 32 bytes / uint256 to simplify decoding
        data = abi.encode(price);
    }

    receive() external payable {}
}

File 2 of 25 : IERC20.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

interface IERC20 {
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Transfer(address indexed from, address indexed to, uint256 value);

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

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

    function decimals() external view returns (uint8);

    function totalSupply() external view returns (uint256);

    function balanceOf(address owner) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);

    function transfer(address to, uint256 value) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool);
}

File 3 of 25 : TwapOracle.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

import './interfaces/ITwapOracle.sol';
import './interfaces/IERC20.sol';
import './libraries/SafeMath.sol';
import '@uniswap/v2-periphery/contracts/libraries/UniswapV2OracleLibrary.sol';

contract TwapOracle is ITwapOracle {
    using SafeMath for uint256;
    using SafeMath for int256;
    uint8 public immutable override xDecimals;
    uint8 public immutable override yDecimals;
    int256 public immutable override decimalsConverter;
    address public override owner;
    address public override uniswapPair;

    constructor(uint8 _xDecimals, uint8 _yDecimals) {
        require(_xDecimals <= 75 && _yDecimals <= 75, 'TO4F');
        if (_yDecimals > _xDecimals) {
            require(_yDecimals - _xDecimals <= 18, 'TO47');
        } else {
            require(_xDecimals - _yDecimals <= 18, 'TO47');
        }
        owner = msg.sender;
        xDecimals = _xDecimals;
        yDecimals = _yDecimals;
        decimalsConverter = (10**(18 + _xDecimals - _yDecimals)).toInt256();

        emit OwnerSet(msg.sender);
    }

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

    function setOwner(address _owner) external override {
        require(msg.sender == owner, 'TO00');
        require(_owner != address(0), 'TO02');
        require(_owner != owner, 'TO01');
        owner = _owner;
        emit OwnerSet(_owner);
    }

    function setUniswapPair(address _uniswapPair) external override {
        require(msg.sender == owner, 'TO00');
        require(_uniswapPair != uniswapPair, 'TO01');
        require(_uniswapPair != address(0), 'TO02');
        require(isContract(_uniswapPair), 'TO0B');
        uniswapPair = _uniswapPair;

        IUniswapV2Pair pairContract = IUniswapV2Pair(_uniswapPair);
        require(
            IERC20(pairContract.token0()).decimals() == xDecimals &&
                IERC20(pairContract.token1()).decimals() == yDecimals,
            'TO45'
        );

        (uint112 reserve0, uint112 reserve1, ) = pairContract.getReserves();
        require(reserve0 != 0 && reserve1 != 0, 'TO1F');
        emit UniswapPairSet(_uniswapPair);
    }

    // based on: https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2OracleLibrary.sol
    function getPriceInfo() public view override returns (uint256 priceAccumulator, uint32 priceTimestamp) {
        IUniswapV2Pair pair = IUniswapV2Pair(uniswapPair);
        priceAccumulator = pair.price0CumulativeLast();
        (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = pair.getReserves();

        // uint32 can be cast directly until Sun, 07 Feb 2106 06:28:15 GMT
        priceTimestamp = uint32(block.timestamp);
        if (blockTimestampLast != priceTimestamp) {
            // allow overflow to stay consistent with Uniswap code and save some gas
            uint32 timeElapsed = priceTimestamp - blockTimestampLast;
            priceAccumulator += uint256(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed;
        }
    }

    function decodePriceInfo(bytes memory data) internal pure returns (uint256 price) {
        assembly {
            price := mload(add(data, 32))
        }
    }

    function getSpotPrice() external view override returns (uint256) {
        (uint112 reserve0, uint112 reserve1, ) = IUniswapV2Pair(uniswapPair).getReserves();
        return uint256(reserve1).mul(uint256(decimalsConverter)).div(uint256(reserve0));
    }

    function getAveragePrice(uint256 priceAccumulator, uint32 priceTimestamp) public view override returns (uint256) {
        (uint256 currentPriceAccumulator, uint32 currentPriceTimestamp) = getPriceInfo();

        require(priceTimestamp < currentPriceTimestamp, 'TO20');

        // timeElapsed = currentPriceTimestamp - priceTimestamp (overflow is desired)
        // averagePrice = (currentPriceAccumulator - priceAccumulator) / timeElapsed
        // return value = (averagePrice * decimalsConverter) / 2**112
        return
            ((currentPriceAccumulator - priceAccumulator) / (currentPriceTimestamp - priceTimestamp)).mul(
                uint256(decimalsConverter)
            ) >> 112;
    }

    function tradeX(
        uint256 xAfter,
        uint256 xBefore,
        uint256 yBefore,
        bytes calldata data
    ) external view override returns (uint256 yAfter) {
        int256 xAfterInt = xAfter.toInt256();
        int256 xBeforeInt = xBefore.toInt256();
        int256 yBeforeInt = yBefore.toInt256();
        int256 averagePriceInt = decodePriceInfo(data).toInt256();

        int256 yTradedInt = xAfterInt.sub(xBeforeInt).mul(averagePriceInt);

        // yAfter = yBefore - yTraded = yBefore - ((xAfter - xBefore) * price)
        // we are multiplying yBefore by decimalsConverter to push division to the very end
        int256 yAfterInt = yBeforeInt.mul(decimalsConverter).sub(yTradedInt).div(decimalsConverter);
        require(yAfterInt >= 0, 'TO27');
        yAfter = uint256(yAfterInt);
    }

    function tradeY(
        uint256 yAfter,
        uint256 xBefore,
        uint256 yBefore,
        bytes calldata data
    ) external view override returns (uint256 xAfter) {
        int256 yAfterInt = yAfter.toInt256();
        int256 xBeforeInt = xBefore.toInt256();
        int256 yBeforeInt = yBefore.toInt256();
        int256 averagePriceInt = decodePriceInfo(data).toInt256();

        int256 xTradedInt = yAfterInt.sub(yBeforeInt).mul(decimalsConverter);

        // xAfter = xBefore - xTraded = xBefore - ((yAfter - yBefore) * price)
        // we are multiplying xBefore by averagePriceInt to push division to the very end
        int256 xAfterInt = xBeforeInt.mul(averagePriceInt).sub(xTradedInt).div(averagePriceInt);
        require(xAfterInt >= 0, 'TO28');

        xAfter = uint256(xAfterInt);
    }

    function depositTradeXIn(
        uint256 xLeft,
        uint256 xBefore,
        uint256 yBefore,
        bytes calldata data
    ) external view override returns (uint256) {
        if (xBefore == 0 || yBefore == 0) {
            return 0;
        }

        // ratio after swap = ratio after second mint
        // (xBefore + xIn) / (yBefore - xIn * price) = (xBefore + xLeft) / yBefore
        // xIn = xLeft * yBefore / (price * (xLeft + xBefore) + yBefore)
        uint256 price = decodePriceInfo(data);
        uint256 numerator = xLeft.mul(yBefore);
        uint256 denominator = price.mul(xLeft.add(xBefore)).add(yBefore.mul(uint256(decimalsConverter)));
        uint256 xIn = numerator.mul(uint256(decimalsConverter)).div(denominator);

        // Don't swap when numbers are too large. This should actually never happen.
        if (xIn.mul(price).div(uint256(decimalsConverter)) >= yBefore || xIn >= xLeft) {
            return 0;
        }

        return xIn;
    }

    function depositTradeYIn(
        uint256 yLeft,
        uint256 xBefore,
        uint256 yBefore,
        bytes calldata data
    ) external view override returns (uint256) {
        if (xBefore == 0 || yBefore == 0) {
            return 0;
        }

        // ratio after swap = ratio after second mint
        // (xBefore - yIn / price) / (yBefore + yIn) = xBefore / (yBefore + yLeft)
        // yIn = price * xBefore * yLeft / (price * xBefore + yLeft + yBefore)
        uint256 price = decodePriceInfo(data);
        uint256 numerator = price.mul(xBefore).mul(yLeft);
        uint256 denominator = price.mul(xBefore).add(yLeft.add(yBefore).mul(uint256(decimalsConverter)));
        uint256 yIn = numerator.div(denominator);

        // Don't swap when numbers are too large. This should actually never happen.
        if (yIn.mul(uint256(decimalsConverter)).div(price) >= xBefore || yIn >= yLeft) {
            return 0;
        }

        return yIn;
    }
}

File 4 of 25 : ITwapOracle.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

interface ITwapOracle {
    event OwnerSet(address owner);
    event UniswapPairSet(address uniswapPair);

    function decimalsConverter() external view returns (int256);

    function xDecimals() external view returns (uint8);

    function yDecimals() external view returns (uint8);

    function owner() external view returns (address);

    function uniswapPair() external view returns (address);

    function getPriceInfo() external view returns (uint256 priceAccumulator, uint32 priceTimestamp);

    function getSpotPrice() external view returns (uint256);

    function getAveragePrice(uint256 priceAccumulator, uint32 priceTimestamp) external view returns (uint256);

    function setOwner(address _owner) external;

    function setUniswapPair(address _uniswapPair) external;

    function tradeX(
        uint256 xAfter,
        uint256 xBefore,
        uint256 yBefore,
        bytes calldata data
    ) external view returns (uint256 yAfter);

    function tradeY(
        uint256 yAfter,
        uint256 yBefore,
        uint256 xBefore,
        bytes calldata data
    ) external view returns (uint256 xAfter);

    function depositTradeXIn(
        uint256 xLeft,
        uint256 xBefore,
        uint256 yBefore,
        bytes calldata data
    ) external view returns (uint256 xIn);

    function depositTradeYIn(
        uint256 yLeft,
        uint256 yBefore,
        uint256 xBefore,
        bytes calldata data
    ) external view returns (uint256 yIn);
}

File 5 of 25 : SafeMath.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)

library SafeMath {
    int256 private constant _INT256_MIN = -2**255;

    function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x + y) >= x, 'SM4E');
    }

    function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = sub(x, y, 'SM12');
    }

    function sub(
        uint256 x,
        uint256 y,
        string memory message
    ) internal pure returns (uint256 z) {
        require((z = x - y) <= x, message);
    }

    function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require(y == 0 || (z = x * y) / y == x, 'SM2A');
    }

    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, 'SM43');
        uint256 c = a / b;
        return c;
    }

    function ceil_div(uint256 a, uint256 b) internal pure returns (uint256 c) {
        c = div(a, b);
        if (c == mul(a, b)) {
            return c;
        } else {
            return add(c, 1);
        }
    }

    function toUint32(uint256 n) internal pure returns (uint32) {
        require(n <= type(uint32).max, 'SM50');
        return uint32(n);
    }

    function toUint112(uint256 n) internal pure returns (uint112) {
        require(n <= type(uint112).max, 'SM51');
        return uint112(n);
    }

    function toInt256(uint256 unsigned) internal pure returns (int256 signed) {
        require(unsigned <= uint256(type(int256).max), 'SM34');
        signed = int256(unsigned);
    }

    // int256

    function add(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a + b;
        require((b >= 0 && c >= a) || (b < 0 && c < a), 'SM4D');

        return c;
    }

    function sub(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a - b;
        require((b >= 0 && c <= a) || (b < 0 && c > a), 'SM11');

        return c;
    }

    function mul(int256 a, int256 b) internal pure returns (int256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        require(!(a == -1 && b == _INT256_MIN), 'SM29');

        int256 c = a * b;
        require(c / a == b, 'SM29');

        return c;
    }

    function div(int256 a, int256 b) internal pure returns (int256) {
        require(b != 0, 'SM43');
        require(!(b == -1 && a == _INT256_MIN), 'SM42');

        int256 c = a / b;

        return c;
    }
}

File 6 of 25 : UniswapV2OracleLibrary.sol
pragma solidity >=0.5.0;

import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';
import '@uniswap/lib/contracts/libraries/FixedPoint.sol';

// library with helper methods for oracles that are concerned with computing average prices
library UniswapV2OracleLibrary {
    using FixedPoint for *;

    // helper function that returns the current block timestamp within the range of uint32, i.e. [0, 2**32 - 1]
    function currentBlockTimestamp() internal view returns (uint32) {
        return uint32(block.timestamp % 2 ** 32);
    }

    // produces the cumulative price using counterfactuals to save gas and avoid a call to sync.
    function currentCumulativePrices(
        address pair
    ) internal view returns (uint price0Cumulative, uint price1Cumulative, uint32 blockTimestamp) {
        blockTimestamp = currentBlockTimestamp();
        price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast();
        price1Cumulative = IUniswapV2Pair(pair).price1CumulativeLast();

        // if time has elapsed since the last update on the pair, mock the accumulated price values
        (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = IUniswapV2Pair(pair).getReserves();
        if (blockTimestampLast != blockTimestamp) {
            // subtraction overflow is desired
            uint32 timeElapsed = blockTimestamp - blockTimestampLast;
            // addition overflow is desired
            // counterfactual
            price0Cumulative += uint(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed;
            // counterfactual
            price1Cumulative += uint(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed;
        }
    }
}

File 7 of 25 : IUniswapV2Pair.sol
pragma solidity >=0.5.0;

interface IUniswapV2Pair {
    event Approval(address indexed owner, address indexed spender, uint value);
    event Transfer(address indexed from, address indexed to, uint value);

    function name() external pure returns (string memory);
    function symbol() external pure returns (string memory);
    function decimals() external pure returns (uint8);
    function totalSupply() external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint value) external returns (bool);
    function transfer(address to, uint value) external returns (bool);
    function transferFrom(address from, address to, uint value) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function PERMIT_TYPEHASH() external pure returns (bytes32);
    function nonces(address owner) external view returns (uint);

    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;

    event Mint(address indexed sender, uint amount0, uint amount1);
    event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint amount0In,
        uint amount1In,
        uint amount0Out,
        uint amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint);
    function factory() external view returns (address);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function price0CumulativeLast() external view returns (uint);
    function price1CumulativeLast() external view returns (uint);
    function kLast() external view returns (uint);

    function mint(address to) external returns (uint liquidity);
    function burn(address to) external returns (uint amount0, uint amount1);
    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
    function skim(address to) external;
    function sync() external;

    function initialize(address, address) external;
}

File 8 of 25 : FixedPoint.sol
pragma solidity >=0.4.0;

// a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))
library FixedPoint {
    // range: [0, 2**112 - 1]
    // resolution: 1 / 2**112
    struct uq112x112 {
        uint224 _x;
    }

    // range: [0, 2**144 - 1]
    // resolution: 1 / 2**112
    struct uq144x112 {
        uint _x;
    }

    uint8 private constant RESOLUTION = 112;

    // encode a uint112 as a UQ112x112
    function encode(uint112 x) internal pure returns (uq112x112 memory) {
        return uq112x112(uint224(x) << RESOLUTION);
    }

    // encodes a uint144 as a UQ144x112
    function encode144(uint144 x) internal pure returns (uq144x112 memory) {
        return uq144x112(uint256(x) << RESOLUTION);
    }

    // divide a UQ112x112 by a uint112, returning a UQ112x112
    function div(uq112x112 memory self, uint112 x) internal pure returns (uq112x112 memory) {
        require(x != 0, 'FixedPoint: DIV_BY_ZERO');
        return uq112x112(self._x / uint224(x));
    }

    // multiply a UQ112x112 by a uint, returning a UQ144x112
    // reverts on overflow
    function mul(uq112x112 memory self, uint y) internal pure returns (uq144x112 memory) {
        uint z;
        require(y == 0 || (z = uint(self._x) * y) / y == uint(self._x), "FixedPoint: MULTIPLICATION_OVERFLOW");
        return uq144x112(z);
    }

    // returns a UQ112x112 which represents the ratio of the numerator to the denominator
    // equivalent to encode(numerator).div(denominator)
    function fraction(uint112 numerator, uint112 denominator) internal pure returns (uq112x112 memory) {
        require(denominator > 0, "FixedPoint: DIV_BY_ZERO");
        return uq112x112((uint224(numerator) << RESOLUTION) / denominator);
    }

    // decode a UQ112x112 into a uint112 by truncating after the radix point
    function decode(uq112x112 memory self) internal pure returns (uint112) {
        return uint112(self._x >> RESOLUTION);
    }

    // decode a UQ144x112 into a uint144 by truncating after the radix point
    function decode144(uq144x112 memory self) internal pure returns (uint144) {
        return uint144(self._x >> RESOLUTION);
    }
}

File 9 of 25 : ITwapPair.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

import './ITwapERC20.sol';
import './IReserves.sol';

interface ITwapPair is ITwapERC20, IReserves {
    event Mint(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 liquidityOut, address indexed to);
    event Burn(address indexed sender, uint256 amount0Out, uint256 amount1Out, uint256 liquidityIn, address indexed to);
    event Swap(
        address indexed sender,
        uint256 amount0In,
        uint256 amount1In,
        uint256 amount0Out,
        uint256 amount1Out,
        address indexed to
    );
    event SetMintFee(uint256 fee);
    event SetBurnFee(uint256 fee);
    event SetSwapFee(uint256 fee);
    event SetOracle(address account);
    event SetTrader(address trader);

    function MINIMUM_LIQUIDITY() external pure returns (uint256);

    function factory() external view returns (address);

    function token0() external view returns (address);

    function token1() external view returns (address);

    function oracle() external view returns (address);

    function trader() external view returns (address);

    function mintFee() external view returns (uint256);

    function setMintFee(uint256 fee) external;

    function mint(address to) external returns (uint256 liquidity);

    function burnFee() external view returns (uint256);

    function setBurnFee(uint256 fee) external;

    function burn(address to) external returns (uint256 amount0, uint256 amount1);

    function swapFee() external view returns (uint256);

    function setSwapFee(uint256 fee) external;

    function setOracle(address account) external;

    function setTrader(address account) external;

    function collect(address to) external;

    function swap(
        uint256 amount0Out,
        uint256 amount1Out,
        address to,
        bytes calldata data
    ) external;

    function sync() external;

    function initialize(
        address _token0,
        address _token1,
        address _oracle,
        address _trader
    ) external;

    function getSwapAmount0In(uint256 amount1Out, bytes calldata data) external view returns (uint256 swapAmount0In);

    function getSwapAmount1In(uint256 amount0Out, bytes calldata data) external view returns (uint256 swapAmount1In);

    function getSwapAmount0Out(uint256 amount1In, bytes calldata data) external view returns (uint256 swapAmount0Out);

    function getSwapAmount1Out(uint256 amount0In, bytes calldata data) external view returns (uint256 swapAmount1Out);

    function getDepositAmount0In(uint256 amount0, bytes calldata data) external view returns (uint256 depositAmount0In);

    function getDepositAmount1In(uint256 amount1, bytes calldata data) external view returns (uint256 depositAmount1In);
}

File 10 of 25 : ITwapDelay.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;
pragma abicoder v2;

import '../libraries/Orders.sol';

interface ITwapDelay {
    event OrderExecuted(uint256 indexed id, bool indexed success, bytes data, uint256 gasSpent, uint256 ethRefunded);
    event RefundFailed(address indexed to, address indexed token, uint256 amount, bytes data);
    event EthRefund(address indexed to, bool indexed success, uint256 value);
    event OwnerSet(address owner);
    event BotSet(address bot, bool isBot);
    event DelaySet(uint256 delay);
    event MaxGasLimitSet(uint256 maxGasLimit);
    event GasPriceInertiaSet(uint256 gasPriceInertia);
    event MaxGasPriceImpactSet(uint256 maxGasPriceImpact);
    event TransferGasCostSet(address token, uint256 gasCost);
    event OrderDisabled(address pair, Orders.OrderType orderType, bool disabled);
    event UnwrapFailed(address to, uint256 amount);
    event Execute(address sender, uint256 n);

    function factory() external returns (address);

    function owner() external returns (address);

    function isBot(address bot) external returns (bool);

    function gasPriceInertia() external returns (uint256);

    function gasPrice() external returns (uint256);

    function maxGasPriceImpact() external returns (uint256);

    function maxGasLimit() external returns (uint256);

    function delay() external returns (uint32);

    function totalShares(address token) external returns (uint256);

    function weth() external returns (address);

    function getTransferGasCost(address token) external returns (uint256);

    function getDepositOrder(uint256 orderId) external returns (Orders.DepositOrder memory order);

    function getWithdrawOrder(uint256 orderId) external returns (Orders.WithdrawOrder memory order);

    function getSellOrder(uint256 orderId) external returns (Orders.SellOrder memory order);

    function getBuyOrder(uint256 orderId) external returns (Orders.BuyOrder memory order);

    function getDepositDisabled(address pair) external returns (bool);

    function getWithdrawDisabled(address pair) external returns (bool);

    function getBuyDisabled(address pair) external returns (bool);

    function getSellDisabled(address pair) external returns (bool);

    function getOrderStatus(uint256 orderId) external returns (Orders.OrderStatus);

    function setOrderDisabled(
        address pair,
        Orders.OrderType orderType,
        bool disabled
    ) external;

    function setOwner(address _owner) external;

    function setBot(address _bot, bool _isBot) external;

    function setMaxGasLimit(uint256 _maxGasLimit) external;

    function setDelay(uint32 _delay) external;

    function setGasPriceInertia(uint256 _gasPriceInertia) external;

    function setMaxGasPriceImpact(uint256 _maxGasPriceImpact) external;

    function setTransferGasCost(address token, uint256 gasCost) external;

    function deposit(Orders.DepositParams memory depositParams) external payable returns (uint256 orderId);

    function withdraw(Orders.WithdrawParams memory withdrawParams) external payable returns (uint256 orderId);

    function sell(Orders.SellParams memory sellParams) external payable returns (uint256 orderId);

    function buy(Orders.BuyParams memory buyParams) external payable returns (uint256 orderId);

    function execute(uint256 n) external;

    function retryRefund(uint256 orderId) external;

    function cancelOrder(uint256 orderId) external;
}

File 11 of 25 : IWETH.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

interface IWETH {
    function deposit() external payable;

    function transfer(address to, uint256 value) external returns (bool);

    function withdraw(uint256) external;
}

File 12 of 25 : Orders.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;
pragma abicoder v2;

import './SafeMath.sol';
import '../libraries/Math.sol';
import '../interfaces/ITwapFactory.sol';
import '../interfaces/ITwapPair.sol';
import '../interfaces/ITwapOracle.sol';
import '../libraries/TokenShares.sol';

library Orders {
    using SafeMath for uint256;
    using TokenShares for TokenShares.Data;
    using TransferHelper for address;

    enum OrderType {
        Empty,
        Deposit,
        Withdraw,
        Sell,
        Buy
    }
    enum OrderStatus {
        NonExistent,
        EnqueuedWaiting,
        EnqueuedReady,
        ExecutedSucceeded,
        ExecutedFailed,
        Canceled
    }

    event MaxGasLimitSet(uint256 maxGasLimit);
    event GasPriceInertiaSet(uint256 gasPriceInertia);
    event MaxGasPriceImpactSet(uint256 maxGasPriceImpact);
    event TransferGasCostSet(address token, uint256 gasCost);

    event DepositEnqueued(uint256 indexed orderId, uint32 validAfterTimestamp, uint256 gasPrice);
    event WithdrawEnqueued(uint256 indexed orderId, uint32 validAfterTimestamp, uint256 gasPrice);
    event SellEnqueued(uint256 indexed orderId, uint32 validAfterTimestamp, uint256 gasPrice);
    event BuyEnqueued(uint256 indexed orderId, uint32 validAfterTimestamp, uint256 gasPrice);

    event OrderDisabled(address pair, Orders.OrderType orderType, bool disabled);

    uint8 private constant DEPOSIT_TYPE = 1;
    uint8 private constant WITHDRAW_TYPE = 2;
    uint8 private constant BUY_TYPE = 3;
    uint8 private constant BUY_INVERTED_TYPE = 4;
    uint8 private constant SELL_TYPE = 5;
    uint8 private constant SELL_INVERTED_TYPE = 6;

    uint8 private constant UNWRAP_NOT_FAILED = 0;
    uint8 private constant KEEP_NOT_FAILED = 1;
    uint8 private constant UNWRAP_FAILED = 2;
    uint8 private constant KEEP_FAILED = 3;

    uint256 private constant ETHER_TRANSFER_COST = 2600 + 1504; // EIP-2929 acct access cost + Gnosis Safe receive ETH cost
    uint256 private constant BUFFER_COST = 10000;
    uint256 private constant ORDER_EXECUTED_EVENT_COST = 3700;
    uint256 private constant EXECUTE_PREPARATION_COST = 55000; // dequeue + getPair in execute

    uint256 public constant ETHER_TRANSFER_CALL_COST = 10000;
    uint256 public constant PAIR_TRANSFER_COST = 55000;
    uint256 public constant REFUND_BASE_COST = 2 * ETHER_TRANSFER_COST + BUFFER_COST + ORDER_EXECUTED_EVENT_COST;
    uint256 public constant ORDER_BASE_COST = EXECUTE_PREPARATION_COST + REFUND_BASE_COST;

    // Masks used for setting order disabled
    // Different bits represent different order types
    uint8 private constant DEPOSIT_MASK = uint8(1) << uint8(OrderType.Deposit); //   00000010
    uint8 private constant WITHDRAW_MASK = uint8(1) << uint8(OrderType.Withdraw); // 00000100
    uint8 private constant SELL_MASK = uint8(1) << uint8(OrderType.Sell); //         00001000
    uint8 private constant BUY_MASK = uint8(1) << uint8(OrderType.Buy); //           00010000

    struct PairInfo {
        address pair;
        address token0;
        address token1;
    }

    struct Data {
        uint32 delay;
        uint256 newestOrderId;
        uint256 lastProcessedOrderId;
        mapping(uint256 => StoredOrder) orderQueue;
        address factory;
        uint256 maxGasLimit;
        uint256 gasPrice;
        uint256 gasPriceInertia;
        uint256 maxGasPriceImpact;
        mapping(uint32 => PairInfo) pairs;
        mapping(address => uint256) transferGasCosts;
        mapping(uint256 => bool) canceled;
        // Bit on specific positions indicates whether order type is disabled (1) or enabled (0) on specific pair
        mapping(address => uint8) orderDisabled;
    }

    struct StoredOrder {
        // slot 0
        uint8 orderType;
        uint32 validAfterTimestamp;
        uint8 unwrapAndFailure;
        uint32 timestamp;
        uint32 gasLimit;
        uint32 gasPrice;
        uint112 liquidity;
        // slot 1
        uint112 value0;
        uint112 value1;
        uint32 pairId;
        // slot2
        address to;
        uint32 minSwapPrice;
        uint32 maxSwapPrice;
        bool swap;
        // slot3
        uint256 priceAccumulator;
    }

    struct DepositOrder {
        uint32 pairId;
        uint256 share0;
        uint256 share1;
        uint256 minSwapPrice;
        uint256 maxSwapPrice;
        bool unwrap;
        bool swap;
        address to;
        uint256 gasPrice;
        uint256 gasLimit;
        uint32 validAfterTimestamp;
        uint256 priceAccumulator;
        uint32 timestamp;
    }

    struct WithdrawOrder {
        uint32 pairId;
        uint256 liquidity;
        uint256 amount0Min;
        uint256 amount1Min;
        bool unwrap;
        address to;
        uint256 gasPrice;
        uint256 gasLimit;
        uint32 validAfterTimestamp;
    }

    struct SellOrder {
        uint32 pairId;
        bool inverse;
        uint256 shareIn;
        uint256 amountOutMin;
        bool unwrap;
        address to;
        uint256 gasPrice;
        uint256 gasLimit;
        uint32 validAfterTimestamp;
        uint256 priceAccumulator;
        uint32 timestamp;
    }

    struct BuyOrder {
        uint32 pairId;
        bool inverse;
        uint256 shareInMax;
        uint256 amountOut;
        bool unwrap;
        address to;
        uint256 gasPrice;
        uint256 gasLimit;
        uint32 validAfterTimestamp;
        uint256 priceAccumulator;
        uint32 timestamp;
    }

    function decodeType(uint256 internalType) internal pure returns (OrderType orderType) {
        if (internalType == DEPOSIT_TYPE) {
            orderType = OrderType.Deposit;
        } else if (internalType == WITHDRAW_TYPE) {
            orderType = OrderType.Withdraw;
        } else if (internalType == BUY_TYPE) {
            orderType = OrderType.Buy;
        } else if (internalType == BUY_INVERTED_TYPE) {
            orderType = OrderType.Buy;
        } else if (internalType == SELL_TYPE) {
            orderType = OrderType.Sell;
        } else if (internalType == SELL_INVERTED_TYPE) {
            orderType = OrderType.Sell;
        } else {
            orderType = OrderType.Empty;
        }
    }

    function getOrder(Data storage data, uint256 orderId)
        public
        view
        returns (OrderType orderType, uint32 validAfterTimestamp)
    {
        StoredOrder storage order = data.orderQueue[orderId];
        uint8 internalType = order.orderType;
        validAfterTimestamp = order.validAfterTimestamp;
        orderType = decodeType(internalType);
    }

    function getOrderStatus(Data storage data, uint256 orderId) external view returns (OrderStatus orderStatus) {
        if (orderId > data.newestOrderId) {
            return OrderStatus.NonExistent;
        }
        if (data.canceled[orderId]) {
            return OrderStatus.Canceled;
        }
        if (isRefundFailed(data, orderId)) {
            return OrderStatus.ExecutedFailed;
        }
        (OrderType orderType, uint32 validAfterTimestamp) = getOrder(data, orderId);
        if (orderType == OrderType.Empty) {
            return OrderStatus.ExecutedSucceeded;
        }
        if (validAfterTimestamp >= block.timestamp) {
            return OrderStatus.EnqueuedWaiting;
        }
        return OrderStatus.EnqueuedReady;
    }

    function getPair(
        Data storage data,
        address tokenA,
        address tokenB
    )
        internal
        returns (
            address pair,
            uint32 pairId,
            bool inverted
        )
    {
        inverted = tokenA > tokenB;
        (address token0, address token1) = inverted ? (tokenB, tokenA) : (tokenA, tokenB);
        pair = ITwapFactory(data.factory).getPair(token0, token1);
        require(pair != address(0), 'OS17');
        pairId = uint32(bytes4(keccak256(abi.encodePacked(pair))));
        if (data.pairs[pairId].pair == address(0)) {
            data.pairs[pairId] = PairInfo(pair, token0, token1);
        }
    }

    function getPairInfo(Data storage data, uint32 pairId)
        external
        view
        returns (
            address pair,
            address token0,
            address token1
        )
    {
        PairInfo storage info = data.pairs[pairId];
        pair = info.pair;
        token0 = info.token0;
        token1 = info.token1;
    }

    function getDepositDisabled(Data storage data, address pair) public view returns (bool) {
        return data.orderDisabled[pair] & DEPOSIT_MASK != 0;
    }

    function getWithdrawDisabled(Data storage data, address pair) public view returns (bool) {
        return data.orderDisabled[pair] & WITHDRAW_MASK != 0;
    }

    function getSellDisabled(Data storage data, address pair) public view returns (bool) {
        return data.orderDisabled[pair] & SELL_MASK != 0;
    }

    function getBuyDisabled(Data storage data, address pair) public view returns (bool) {
        return data.orderDisabled[pair] & BUY_MASK != 0;
    }

    function getDepositOrder(Data storage data, uint256 index) public view returns (DepositOrder memory order) {
        StoredOrder memory stored = data.orderQueue[index];
        require(stored.orderType == DEPOSIT_TYPE, 'OS32');
        order.pairId = stored.pairId;
        order.share0 = stored.value0;
        order.share1 = stored.value1;
        order.minSwapPrice = float32ToUint(stored.minSwapPrice);
        order.maxSwapPrice = float32ToUint(stored.maxSwapPrice);
        order.unwrap = getUnwrap(stored.unwrapAndFailure);
        order.swap = stored.swap;
        order.to = stored.to;
        order.gasPrice = uint32ToGasPrice(stored.gasPrice);
        order.gasLimit = stored.gasLimit;
        order.validAfterTimestamp = stored.validAfterTimestamp;
        order.priceAccumulator = stored.priceAccumulator;
        order.timestamp = stored.timestamp;
    }

    function getWithdrawOrder(Data storage data, uint256 index) public view returns (WithdrawOrder memory order) {
        StoredOrder memory stored = data.orderQueue[index];
        require(stored.orderType == WITHDRAW_TYPE, 'OS32');
        order.pairId = stored.pairId;
        order.liquidity = stored.liquidity;
        order.amount0Min = stored.value0;
        order.amount1Min = stored.value1;
        order.unwrap = getUnwrap(stored.unwrapAndFailure);
        order.to = stored.to;
        order.gasPrice = uint32ToGasPrice(stored.gasPrice);
        order.gasLimit = stored.gasLimit;
        order.validAfterTimestamp = stored.validAfterTimestamp;
    }

    function getSellOrder(Data storage data, uint256 index) public view returns (SellOrder memory order) {
        StoredOrder memory stored = data.orderQueue[index];
        require(stored.orderType == SELL_TYPE || stored.orderType == SELL_INVERTED_TYPE, 'OS32');
        order.pairId = stored.pairId;
        order.inverse = stored.orderType == SELL_INVERTED_TYPE;
        order.shareIn = stored.value0;
        order.amountOutMin = stored.value1;
        order.unwrap = getUnwrap(stored.unwrapAndFailure);
        order.to = stored.to;
        order.gasPrice = uint32ToGasPrice(stored.gasPrice);
        order.gasLimit = stored.gasLimit;
        order.validAfterTimestamp = stored.validAfterTimestamp;
        order.priceAccumulator = stored.priceAccumulator;
        order.timestamp = stored.timestamp;
    }

    function getBuyOrder(Data storage data, uint256 index) public view returns (BuyOrder memory order) {
        StoredOrder memory stored = data.orderQueue[index];
        require(stored.orderType == BUY_TYPE || stored.orderType == BUY_INVERTED_TYPE, 'OS32');
        order.pairId = stored.pairId;
        order.inverse = stored.orderType == BUY_INVERTED_TYPE;
        order.shareInMax = stored.value0;
        order.amountOut = stored.value1;
        order.unwrap = getUnwrap(stored.unwrapAndFailure);
        order.to = stored.to;
        order.gasPrice = uint32ToGasPrice(stored.gasPrice);
        order.gasLimit = stored.gasLimit;
        order.validAfterTimestamp = stored.validAfterTimestamp;
        order.timestamp = stored.timestamp;
        order.priceAccumulator = stored.priceAccumulator;
    }

    function getFailedOrderType(Data storage data, uint256 orderId)
        external
        view
        returns (OrderType orderType, uint32 validAfterTimestamp)
    {
        require(isRefundFailed(data, orderId), 'OS21');
        (orderType, validAfterTimestamp) = getOrder(data, orderId);
    }

    function getUnwrap(uint8 unwrapAndFailure) private pure returns (bool) {
        return unwrapAndFailure == UNWRAP_FAILED || unwrapAndFailure == UNWRAP_NOT_FAILED;
    }

    function getUnwrapAndFailure(bool unwrap) private pure returns (uint8) {
        return unwrap ? UNWRAP_NOT_FAILED : KEEP_NOT_FAILED;
    }

    function timestampToUint32(uint256 timestamp) private pure returns (uint32 timestamp32) {
        if (timestamp == type(uint256).max) {
            return type(uint32).max;
        }
        timestamp32 = timestamp.toUint32();
    }

    function gasPriceToUint32(uint256 gasPrice) private pure returns (uint32 gasPrice32) {
        require((gasPrice / 1e6) * 1e6 == gasPrice, 'OS3C');
        gasPrice32 = (gasPrice / 1e6).toUint32();
    }

    function uint32ToGasPrice(uint32 gasPrice32) public pure returns (uint256 gasPrice) {
        gasPrice = uint256(gasPrice32) * 1e6;
    }

    function uintToFloat32(uint256 number) internal pure returns (uint32 float32) {
        // Number is encoded on 4 bytes. 3 bytes for mantissa and 1 for exponent.
        // If the number fits in the mantissa we set the exponent to zero and return.
        if (number < 2 << 24) {
            return uint32(number << 8);
        }
        // We find the exponent by counting the number of trailing zeroes.
        // Simultaneously we remove those zeroes from the number.
        uint32 exponent;
        for (exponent = 0; exponent < 256 - 24; exponent++) {
            // Last bit is one.
            if (number & 1 == 1) {
                break;
            }
            number = number >> 1;
        }
        // The number must fit in the mantissa.
        require(number < 2 << 24, 'OS1A');
        // Set the first three bytes to the number and the fourth to the exponent.
        float32 = uint32(number << 8) | exponent;
    }

    function float32ToUint(uint32 float32) internal pure returns (uint256 number) {
        // Number is encoded on 4 bytes. 3 bytes for mantissa and 1 for exponent.
        // We get the exponent by extracting the last byte.
        uint256 exponent = float32 & 0xFF;
        // Sanity check. Only triggered for values not encoded with uintToFloat32.
        require(exponent <= 256 - 24, 'OS1B');
        // We get the mantissa by extracting the first three bytes and removing the fourth.
        uint256 mantissa = (float32 & 0xFFFFFF00) >> 8;
        // We add exponent number zeroes after the mantissa.
        number = mantissa << exponent;
    }

    function setOrderDisabled(
        Data storage data,
        address pair,
        Orders.OrderType orderType,
        bool disabled
    ) external {
        require(orderType != Orders.OrderType.Empty, 'OS32');
        uint8 currentSettings = data.orderDisabled[pair];

        // zeros with 1 bit set at position specified by orderType
        uint8 mask = uint8(1) << uint8(orderType);

        // set/unset a bit accordingly to 'disabled' value
        if (disabled) {
            // OR operation to disable order
            // e.g. for disable DEPOSIT
            // currentSettings   = 00010100 (BUY and WITHDRAW disabled)
            // mask for DEPOSIT  = 00000010
            // the result of OR  = 00010110
            currentSettings = currentSettings | mask;
        } else {
            // AND operation with a mask negation to enable order
            // e.g. for enable DEPOSIT
            // currentSettings   = 00010100 (BUY and WITHDRAW disabled)
            // 0xff              = 11111111
            // mask for Deposit  = 00000010
            // mask negation     = 11111101
            // the result of AND = 00010100
            currentSettings = currentSettings & (mask ^ 0xff);
        }
        require(currentSettings != data.orderDisabled[pair], 'OS01');
        data.orderDisabled[pair] = currentSettings;

        emit OrderDisabled(pair, orderType, disabled);
    }

    function enqueueDepositOrder(Data storage data, DepositOrder memory depositOrder) internal {
        data.newestOrderId++;
        emit DepositEnqueued(data.newestOrderId, depositOrder.validAfterTimestamp, depositOrder.gasPrice);
        data.orderQueue[data.newestOrderId] = StoredOrder(
            DEPOSIT_TYPE,
            depositOrder.validAfterTimestamp,
            getUnwrapAndFailure(depositOrder.unwrap),
            depositOrder.timestamp,
            depositOrder.gasLimit.toUint32(),
            gasPriceToUint32(depositOrder.gasPrice),
            0, // liquidity
            depositOrder.share0.toUint112(),
            depositOrder.share1.toUint112(),
            depositOrder.pairId,
            depositOrder.to,
            uintToFloat32(depositOrder.minSwapPrice),
            uintToFloat32(depositOrder.maxSwapPrice),
            depositOrder.swap,
            depositOrder.priceAccumulator
        );
    }

    function enqueueWithdrawOrder(Data storage data, WithdrawOrder memory withdrawOrder) internal {
        data.newestOrderId++;
        emit WithdrawEnqueued(data.newestOrderId, withdrawOrder.validAfterTimestamp, withdrawOrder.gasPrice);
        data.orderQueue[data.newestOrderId] = StoredOrder(
            WITHDRAW_TYPE,
            withdrawOrder.validAfterTimestamp,
            getUnwrapAndFailure(withdrawOrder.unwrap),
            0, // timestamp
            withdrawOrder.gasLimit.toUint32(),
            gasPriceToUint32(withdrawOrder.gasPrice),
            withdrawOrder.liquidity.toUint112(),
            withdrawOrder.amount0Min.toUint112(),
            withdrawOrder.amount1Min.toUint112(),
            withdrawOrder.pairId,
            withdrawOrder.to,
            0, // minSwapPrice
            0, // maxSwapPrice
            false, // swap
            0 // priceAccumulator
        );
    }

    function enqueueSellOrder(Data storage data, SellOrder memory sellOrder) internal {
        data.newestOrderId++;
        emit SellEnqueued(data.newestOrderId, sellOrder.validAfterTimestamp, sellOrder.gasPrice);
        data.orderQueue[data.newestOrderId] = StoredOrder(
            sellOrder.inverse ? SELL_INVERTED_TYPE : SELL_TYPE,
            sellOrder.validAfterTimestamp,
            getUnwrapAndFailure(sellOrder.unwrap),
            sellOrder.timestamp,
            sellOrder.gasLimit.toUint32(),
            gasPriceToUint32(sellOrder.gasPrice),
            0, // liquidity
            sellOrder.shareIn.toUint112(),
            sellOrder.amountOutMin.toUint112(),
            sellOrder.pairId,
            sellOrder.to,
            0, // minSwapPrice
            0, // maxSwapPrice
            false, // swap
            sellOrder.priceAccumulator
        );
    }

    function enqueueBuyOrder(Data storage data, BuyOrder memory buyOrder) internal {
        data.newestOrderId++;
        emit BuyEnqueued(data.newestOrderId, buyOrder.validAfterTimestamp, buyOrder.gasPrice);
        data.orderQueue[data.newestOrderId] = StoredOrder(
            buyOrder.inverse ? BUY_INVERTED_TYPE : BUY_TYPE,
            buyOrder.validAfterTimestamp,
            getUnwrapAndFailure(buyOrder.unwrap),
            buyOrder.timestamp,
            buyOrder.gasLimit.toUint32(),
            gasPriceToUint32(buyOrder.gasPrice),
            0, // liquidity
            buyOrder.shareInMax.toUint112(),
            buyOrder.amountOut.toUint112(),
            buyOrder.pairId,
            buyOrder.to,
            0, // minSwapPrice
            0, // maxSwapPrice
            false, // swap
            buyOrder.priceAccumulator
        );
    }

    function isRefundFailed(Data storage data, uint256 index) internal view returns (bool) {
        uint8 unwrapAndFailure = data.orderQueue[index].unwrapAndFailure;
        return unwrapAndFailure == UNWRAP_FAILED || unwrapAndFailure == KEEP_FAILED;
    }

    function markRefundFailed(Data storage data) internal {
        StoredOrder storage stored = data.orderQueue[data.lastProcessedOrderId];
        stored.unwrapAndFailure = stored.unwrapAndFailure == UNWRAP_NOT_FAILED ? UNWRAP_FAILED : KEEP_FAILED;
    }

    function getNextOrder(Data storage data) internal view returns (OrderType orderType, uint256 validAfterTimestamp) {
        return getOrder(data, data.lastProcessedOrderId + 1);
    }

    function dequeueCanceledOrder(Data storage data) external {
        data.lastProcessedOrderId++;
    }

    function dequeueDepositOrder(Data storage data) external returns (DepositOrder memory order) {
        data.lastProcessedOrderId++;
        order = getDepositOrder(data, data.lastProcessedOrderId);
    }

    function dequeueWithdrawOrder(Data storage data) external returns (WithdrawOrder memory order) {
        data.lastProcessedOrderId++;
        order = getWithdrawOrder(data, data.lastProcessedOrderId);
    }

    function dequeueSellOrder(Data storage data) external returns (SellOrder memory order) {
        data.lastProcessedOrderId++;
        order = getSellOrder(data, data.lastProcessedOrderId);
    }

    function dequeueBuyOrder(Data storage data) external returns (BuyOrder memory order) {
        data.lastProcessedOrderId++;
        order = getBuyOrder(data, data.lastProcessedOrderId);
    }

    function forgetOrder(Data storage data, uint256 orderId) internal {
        delete data.orderQueue[orderId];
    }

    function forgetLastProcessedOrder(Data storage data) internal {
        delete data.orderQueue[data.lastProcessedOrderId];
    }

    struct DepositParams {
        address token0;
        address token1;
        uint256 amount0;
        uint256 amount1;
        uint256 minSwapPrice;
        uint256 maxSwapPrice;
        bool wrap;
        bool swap;
        address to;
        uint256 gasLimit;
        uint32 submitDeadline;
    }

    function deposit(
        Data storage data,
        DepositParams calldata depositParams,
        TokenShares.Data storage tokenShares
    ) external {
        uint256 token0TransferCost = data.transferGasCosts[depositParams.token0];
        uint256 token1TransferCost = data.transferGasCosts[depositParams.token1];
        require(token0TransferCost != 0 && token1TransferCost != 0, 'OS0F');
        checkOrderParams(
            data,
            depositParams.to,
            depositParams.gasLimit,
            depositParams.submitDeadline,
            ORDER_BASE_COST.add(token0TransferCost).add(token1TransferCost)
        );
        require(depositParams.amount0 != 0 || depositParams.amount1 != 0, 'OS25');
        (address pairAddress, uint32 pairId, bool inverted) = getPair(data, depositParams.token0, depositParams.token1);
        require(!getDepositDisabled(data, pairAddress), 'OS46');
        {
            // scope for value, avoids stack too deep errors
            uint256 value = msg.value;

            // allocate gas refund
            if (depositParams.wrap) {
                if (depositParams.token0 == tokenShares.weth) {
                    value = value.sub(depositParams.amount0, 'OS1E');
                } else if (depositParams.token1 == tokenShares.weth) {
                    value = value.sub(depositParams.amount1, 'OS1E');
                }
            }
            allocateGasRefund(data, value, depositParams.gasLimit);
        }

        uint256 shares0 = tokenShares.amountToShares(depositParams.token0, depositParams.amount0, depositParams.wrap);
        uint256 shares1 = tokenShares.amountToShares(depositParams.token1, depositParams.amount1, depositParams.wrap);

        (uint256 priceAccumulator, uint32 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo();
        enqueueDepositOrder(
            data,
            DepositOrder(
                pairId,
                inverted ? shares1 : shares0,
                inverted ? shares0 : shares1,
                depositParams.minSwapPrice,
                depositParams.maxSwapPrice,
                depositParams.wrap,
                depositParams.swap,
                depositParams.to,
                data.gasPrice,
                depositParams.gasLimit,
                timestamp + data.delay, // validAfterTimestamp
                priceAccumulator,
                timestamp
            )
        );
    }

    struct WithdrawParams {
        address token0;
        address token1;
        uint256 liquidity;
        uint256 amount0Min;
        uint256 amount1Min;
        bool unwrap;
        address to;
        uint256 gasLimit;
        uint32 submitDeadline;
    }

    function withdraw(Data storage data, WithdrawParams calldata withdrawParams) external {
        (address pair, uint32 pairId, bool inverted) = getPair(data, withdrawParams.token0, withdrawParams.token1);
        require(!getWithdrawDisabled(data, pair), 'OS0A');
        checkOrderParams(
            data,
            withdrawParams.to,
            withdrawParams.gasLimit,
            withdrawParams.submitDeadline,
            ORDER_BASE_COST.add(PAIR_TRANSFER_COST)
        );
        require(withdrawParams.liquidity != 0, 'OS22');

        allocateGasRefund(data, msg.value, withdrawParams.gasLimit);
        pair.safeTransferFrom(msg.sender, address(this), withdrawParams.liquidity);
        enqueueWithdrawOrder(
            data,
            WithdrawOrder(
                pairId,
                withdrawParams.liquidity,
                inverted ? withdrawParams.amount1Min : withdrawParams.amount0Min,
                inverted ? withdrawParams.amount0Min : withdrawParams.amount1Min,
                withdrawParams.unwrap,
                withdrawParams.to,
                data.gasPrice,
                withdrawParams.gasLimit,
                timestampToUint32(block.timestamp) + data.delay
            )
        );
    }

    struct SellParams {
        address tokenIn;
        address tokenOut;
        uint256 amountIn;
        uint256 amountOutMin;
        bool wrapUnwrap;
        address to;
        uint256 gasLimit;
        uint32 submitDeadline;
    }

    function sell(
        Data storage data,
        SellParams calldata sellParams,
        TokenShares.Data storage tokenShares
    ) external {
        uint256 tokenTransferCost = data.transferGasCosts[sellParams.tokenIn];
        require(tokenTransferCost != 0, 'OS0F');
        checkOrderParams(
            data,
            sellParams.to,
            sellParams.gasLimit,
            sellParams.submitDeadline,
            ORDER_BASE_COST.add(tokenTransferCost)
        );
        require(sellParams.amountIn != 0, 'OS24');
        (address pairAddress, uint32 pairId, bool inverted) = getPair(data, sellParams.tokenIn, sellParams.tokenOut);
        require(!getSellDisabled(data, pairAddress), 'OS13');
        uint256 value = msg.value;

        // allocate gas refund
        if (sellParams.tokenIn == tokenShares.weth && sellParams.wrapUnwrap) {
            value = value.sub(sellParams.amountIn, 'OS1E');
        }
        allocateGasRefund(data, value, sellParams.gasLimit);

        uint256 shares = tokenShares.amountToShares(sellParams.tokenIn, sellParams.amountIn, sellParams.wrapUnwrap);

        (uint256 priceAccumulator, uint32 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo();
        enqueueSellOrder(
            data,
            SellOrder(
                pairId,
                inverted,
                shares,
                sellParams.amountOutMin,
                sellParams.wrapUnwrap,
                sellParams.to,
                data.gasPrice,
                sellParams.gasLimit,
                timestamp + data.delay,
                priceAccumulator,
                timestamp
            )
        );
    }

    struct BuyParams {
        address tokenIn;
        address tokenOut;
        uint256 amountInMax;
        uint256 amountOut;
        bool wrapUnwrap;
        address to;
        uint256 gasLimit;
        uint32 submitDeadline;
    }

    function buy(
        Data storage data,
        BuyParams calldata buyParams,
        TokenShares.Data storage tokenShares
    ) external {
        uint256 tokenTransferCost = data.transferGasCosts[buyParams.tokenIn];
        require(tokenTransferCost != 0, 'OS0F');
        checkOrderParams(
            data,
            buyParams.to,
            buyParams.gasLimit,
            buyParams.submitDeadline,
            ORDER_BASE_COST.add(tokenTransferCost)
        );
        require(buyParams.amountOut != 0, 'OS23');
        (address pairAddress, uint32 pairId, bool inverted) = getPair(data, buyParams.tokenIn, buyParams.tokenOut);
        require(!getBuyDisabled(data, pairAddress), 'OS49');
        uint256 value = msg.value;

        // allocate gas refund
        if (buyParams.tokenIn == tokenShares.weth && buyParams.wrapUnwrap) {
            value = value.sub(buyParams.amountInMax, 'OS1E');
        }
        allocateGasRefund(data, value, buyParams.gasLimit);

        uint256 shares = tokenShares.amountToShares(buyParams.tokenIn, buyParams.amountInMax, buyParams.wrapUnwrap);

        (uint256 priceAccumulator, uint32 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo();
        enqueueBuyOrder(
            data,
            BuyOrder(
                pairId,
                inverted,
                shares,
                buyParams.amountOut,
                buyParams.wrapUnwrap,
                buyParams.to,
                data.gasPrice,
                buyParams.gasLimit,
                timestamp + data.delay,
                priceAccumulator,
                timestamp
            )
        );
    }

    function checkOrderParams(
        Data storage data,
        address to,
        uint256 gasLimit,
        uint32 submitDeadline,
        uint256 minGasLimit
    ) private view {
        require(submitDeadline >= block.timestamp, 'OS04');
        require(gasLimit <= data.maxGasLimit, 'OS3E');
        require(gasLimit >= minGasLimit, 'OS3D');
        require(to != address(0), 'OS26');
    }

    function allocateGasRefund(
        Data storage data,
        uint256 value,
        uint256 gasLimit
    ) private returns (uint256 futureFee) {
        futureFee = data.gasPrice.mul(gasLimit);
        require(value >= futureFee, 'OS1E');
        if (value > futureFee) {
            TransferHelper.safeTransferETH(msg.sender, value.sub(futureFee), data.transferGasCosts[address(0)]);
        }
    }

    function updateGasPrice(Data storage data, uint256 gasUsed) external {
        uint256 scale = Math.min(gasUsed, data.maxGasPriceImpact);
        uint256 updated = data.gasPrice.mul(data.gasPriceInertia.sub(scale)).add(tx.gasprice.mul(scale)).div(
            data.gasPriceInertia
        );
        // we lower the precision for gas savings in order queue
        data.gasPrice = updated - (updated % 1e6);
    }

    function setMaxGasLimit(Data storage data, uint256 _maxGasLimit) external {
        require(_maxGasLimit != data.maxGasLimit, 'OS01');
        require(_maxGasLimit <= 10000000, 'OS2B');
        data.maxGasLimit = _maxGasLimit;
        emit MaxGasLimitSet(_maxGasLimit);
    }

    function setGasPriceInertia(Data storage data, uint256 _gasPriceInertia) external {
        require(_gasPriceInertia != data.gasPriceInertia, 'OS01');
        require(_gasPriceInertia >= 1, 'OS35');
        data.gasPriceInertia = _gasPriceInertia;
        emit GasPriceInertiaSet(_gasPriceInertia);
    }

    function setMaxGasPriceImpact(Data storage data, uint256 _maxGasPriceImpact) external {
        require(_maxGasPriceImpact != data.maxGasPriceImpact, 'OS01');
        require(_maxGasPriceImpact <= data.gasPriceInertia, 'OS33');
        data.maxGasPriceImpact = _maxGasPriceImpact;
        emit MaxGasPriceImpactSet(_maxGasPriceImpact);
    }

    function setTransferGasCost(
        Data storage data,
        address token,
        uint256 gasCost
    ) external {
        require(gasCost != data.transferGasCosts[token], 'OS01');
        data.transferGasCosts[token] = gasCost;
        emit TransferGasCostSet(token, gasCost);
    }
}

File 13 of 25 : TokenShares.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

import '../interfaces/IERC20.sol';
import '../interfaces/IWETH.sol';
import './SafeMath.sol';
import './TransferHelper.sol';

library TokenShares {
    using SafeMath for uint256;
    using TransferHelper for address;

    event UnwrapFailed(address to, uint256 amount);

    struct Data {
        mapping(address => uint256) totalShares;
        address weth;
    }

    function setWeth(Data storage data, address _weth) internal {
        data.weth = _weth;
    }

    function sharesToAmount(
        Data storage data,
        address token,
        uint256 share
    ) external returns (uint256) {
        if (share == 0) {
            return 0;
        }
        if (token == data.weth) {
            return share;
        }
        uint256 totalTokenShares = data.totalShares[token];
        require(totalTokenShares >= share, 'TS3A');
        uint256 balance = IERC20(token).balanceOf(address(this));
        uint256 value = balance.mul(share).div(totalTokenShares);
        data.totalShares[token] = totalTokenShares.sub(share);
        return value;
    }

    function amountToShares(
        Data storage data,
        address token,
        uint256 amount,
        bool wrap
    ) external returns (uint256) {
        if (amount == 0) {
            return 0;
        }
        if (token == data.weth) {
            if (wrap) {
                require(msg.value >= amount, 'TS03');
                IWETH(token).deposit{ value: amount }();
            } else {
                token.safeTransferFrom(msg.sender, address(this), amount);
            }
            return amount;
        } else {
            uint256 balanceBefore = IERC20(token).balanceOf(address(this));
            uint256 totalTokenShares = data.totalShares[token];
            require(balanceBefore > 0 || totalTokenShares == 0, 'TS30');
            if (totalTokenShares == 0) {
                totalTokenShares = balanceBefore;
            }
            token.safeTransferFrom(msg.sender, address(this), amount);
            uint256 balanceAfter = IERC20(token).balanceOf(address(this));
            require(balanceAfter > balanceBefore, 'TS2C');
            if (balanceBefore > 0) {
                uint256 newShares = totalTokenShares.mul(balanceAfter).div(balanceBefore);
                data.totalShares[token] = newShares;
                return newShares - totalTokenShares;
            } else {
                data.totalShares[token] = balanceAfter;
                return balanceAfter;
            }
        }
    }

    function onUnwrapFailed(
        Data storage data,
        address to,
        uint256 amount
    ) external {
        emit UnwrapFailed(to, amount);
        IWETH(data.weth).deposit{ value: amount }();
        TransferHelper.safeTransfer(data.weth, to, amount);
    }
}

File 14 of 25 : AddLiquidity.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

import './TransferHelper.sol';
import './SafeMath.sol';
import './Math.sol';
import '../interfaces/ITwapPair.sol';
import '../interfaces/ITwapOracle.sol';

library AddLiquidity {
    using SafeMath for uint256;

    function _quote(
        uint256 amount0,
        uint256 reserve0,
        uint256 reserve1
    ) private pure returns (uint256 amountB) {
        require(amount0 > 0, 'AL03');
        require(reserve0 > 0 && reserve1 > 0, 'AL07');
        amountB = amount0.mul(reserve1) / reserve0;
    }

    function addLiquidity(
        address pair,
        uint256 amount0Desired,
        uint256 amount1Desired
    ) internal view returns (uint256 amount0, uint256 amount1) {
        if (amount0Desired == 0 || amount1Desired == 0) {
            return (0, 0);
        }
        (uint256 reserve0, uint256 reserve1) = ITwapPair(pair).getReserves();
        if (reserve0 == 0 && reserve1 == 0) {
            (amount0, amount1) = (amount0Desired, amount1Desired);
        } else {
            uint256 amount1Optimal = _quote(amount0Desired, reserve0, reserve1);
            if (amount1Optimal <= amount1Desired) {
                (amount0, amount1) = (amount0Desired, amount1Optimal);
            } else {
                uint256 amount0Optimal = _quote(amount1Desired, reserve1, reserve0);
                assert(amount0Optimal <= amount0Desired);
                (amount0, amount1) = (amount0Optimal, amount1Desired);
            }
        }
    }

    function addLiquidityAndMint(
        address pair,
        address to,
        address token0,
        address token1,
        uint256 amount0Desired,
        uint256 amount1Desired
    ) external returns (uint256 amount0Left, uint256 amount1Left) {
        (uint256 amount0, uint256 amount1) = addLiquidity(pair, amount0Desired, amount1Desired);
        if (amount0 == 0 || amount1 == 0) {
            return (amount0Desired, amount1Desired);
        }
        TransferHelper.safeTransfer(token0, pair, amount0);
        TransferHelper.safeTransfer(token1, pair, amount1);
        ITwapPair(pair).mint(to);

        amount0Left = amount0Desired.sub(amount0);
        amount1Left = amount1Desired.sub(amount1);
    }

    function swapDeposit0(
        address pair,
        address token0,
        uint256 amount0,
        uint256 minSwapPrice,
        bytes calldata data
    ) external returns (uint256 amount0Left, uint256 amount1Left) {
        uint256 amount0In = ITwapPair(pair).getDepositAmount0In(amount0, data);
        amount1Left = ITwapPair(pair).getSwapAmount1Out(amount0In, data);
        if (amount1Left == 0) {
            return (amount0, amount1Left);
        }
        uint256 price = getPrice(amount0In, amount1Left, pair);
        require(minSwapPrice == 0 || price >= minSwapPrice, 'AL15');
        TransferHelper.safeTransfer(token0, pair, amount0In);
        ITwapPair(pair).swap(0, amount1Left, address(this), data);
        amount0Left = amount0.sub(amount0In);
    }

    function swapDeposit1(
        address pair,
        address token1,
        uint256 amount1,
        uint256 maxSwapPrice,
        bytes calldata data
    ) external returns (uint256 amount0Left, uint256 amount1Left) {
        uint256 amount1In = ITwapPair(pair).getDepositAmount1In(amount1, data);
        amount0Left = ITwapPair(pair).getSwapAmount0Out(amount1In, data);
        if (amount0Left == 0) {
            return (amount0Left, amount1);
        }
        uint256 price = getPrice(amount0Left, amount1In, pair);
        require(maxSwapPrice == 0 || price <= maxSwapPrice, 'AL16');
        TransferHelper.safeTransfer(token1, pair, amount1In);
        ITwapPair(pair).swap(amount0Left, 0, address(this), data);
        amount1Left = amount1.sub(amount1In);
    }

    function getPrice(
        uint256 amount0,
        uint256 amount1,
        address pair
    ) internal view returns (uint256) {
        ITwapOracle oracle = ITwapOracle(ITwapPair(pair).oracle());
        return amount1.mul(uint256(oracle.decimalsConverter())).div(amount0);
    }
}

File 15 of 25 : WithdrawHelper.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;
pragma abicoder v2;

import '../interfaces/ITwapPair.sol';
import '../interfaces/IWETH.sol';
import './Orders.sol';

library WithdrawHelper {
    using SafeMath for uint256;

    function _transferToken(
        uint256 balanceBefore,
        address token,
        address to
    ) internal {
        uint256 tokenAmount = IERC20(token).balanceOf(address(this)).sub(balanceBefore);
        TransferHelper.safeTransfer(token, to, tokenAmount);
    }

    function _unwrapWeth(
        uint256 ethAmount,
        address weth,
        address to,
        uint256 gasLimit
    ) internal returns (bool) {
        IWETH(weth).withdraw(ethAmount);
        (bool success, ) = to.call{ value: ethAmount, gas: gasLimit }('');
        return success;
    }

    function withdrawAndUnwrap(
        address token0,
        address token1,
        address pair,
        address weth,
        address to,
        uint256 gasLimit
    )
        external
        returns (
            bool,
            uint256,
            uint256,
            uint256
        )
    {
        bool isToken0Weth = token0 == weth;
        address otherToken = isToken0Weth ? token1 : token0;

        uint256 balanceBefore = IERC20(otherToken).balanceOf(address(this));
        (uint256 amount0, uint256 amount1) = ITwapPair(pair).burn(address(this));
        _transferToken(balanceBefore, otherToken, to);

        bool success = _unwrapWeth(isToken0Weth ? amount0 : amount1, weth, to, gasLimit);

        return (success, isToken0Weth ? amount0 : amount1, amount0, amount1);
    }
}

File 16 of 25 : ITwapERC20.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

import './IERC20.sol';

interface ITwapERC20 is IERC20 {
    function PERMIT_TYPEHASH() external pure returns (bytes32);

    function nonces(address owner) external view returns (uint256);

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);

    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
}

File 17 of 25 : IReserves.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

interface IReserves {
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1);

    function getFees() external view returns (uint256 fee0, uint256 fee1);
}

File 18 of 25 : Math.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

// a library for performing various math operations

library Math {
    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x < y ? x : y;
    }

    function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x > y ? x : y;
    }

    // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
    function sqrt(uint256 y) internal pure returns (uint256 z) {
        if (y > 3) {
            z = y;
            uint256 x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
        } else if (y != 0) {
            z = 1;
        }
    }
}

File 19 of 25 : ITwapFactory.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

interface ITwapFactory {
    event PairCreated(address indexed token0, address indexed token1, address pair, uint256);
    event OwnerSet(address owner);

    function owner() external view returns (address);

    function getPair(address tokenA, address tokenB) external view returns (address pair);

    function allPairs(uint256) external view returns (address pair);

    function allPairsLength() external view returns (uint256);

    function createPair(
        address tokenA,
        address tokenB,
        address oracle,
        address trader
    ) external returns (address pair);

    function setOwner(address) external;

    function setMintFee(
        address tokenA,
        address tokenB,
        uint256 fee
    ) external;

    function setBurnFee(
        address tokenA,
        address tokenB,
        uint256 fee
    ) external;

    function setSwapFee(
        address tokenA,
        address tokenB,
        uint256 fee
    ) external;

    function setOracle(
        address tokenA,
        address tokenB,
        address oracle
    ) external;

    function setTrader(
        address tokenA,
        address tokenB,
        address trader
    ) external;

    function collect(
        address tokenA,
        address tokenB,
        address to
    ) external;

    function withdraw(
        address tokenA,
        address tokenB,
        uint256 amount,
        address to
    ) external;
}

File 20 of 25 : TransferHelper.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
    function safeApprove(
        address token,
        address to,
        uint256 value
    ) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TH4B');
    }

    function safeTransfer(
        address token,
        address to,
        uint256 value
    ) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TH05');
    }

    function safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 value
    ) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TH0E');
    }

    function safeTransferETH(
        address to,
        uint256 value,
        uint256 gasLimit
    ) internal {
        (bool success, ) = to.call{ value: value, gas: gasLimit }('');
        require(success, 'TH3F');
    }

    function transferETH(
        address to,
        uint256 value,
        uint256 gasLimit
    ) internal returns (bool success) {
        (success, ) = to.call{ value: value, gas: gasLimit }('');
    }
}

File 21 of 25 : TwapPair.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

import './interfaces/ITwapPair.sol';
import './libraries/Reserves.sol';
import './TwapLPToken.sol';
import './libraries/Math.sol';
import './interfaces/IERC20.sol';
import './interfaces/ITwapFactory.sol';
import './interfaces/ITwapOracle.sol';

contract TwapPair is Reserves, TwapLPToken, ITwapPair {
    using SafeMath for uint256;

    uint256 private constant PRECISION = 10**18;

    uint256 public override mintFee = 0;
    uint256 public override burnFee = 0;
    uint256 public override swapFee = 0;

    uint256 public constant override MINIMUM_LIQUIDITY = 10**3;

    bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));

    address public immutable override factory;
    address public override token0;
    address public override token1;
    address public override oracle;
    address public override trader;

    uint256 private unlocked = 1;
    modifier lock() {
        require(unlocked == 1, 'TP06');
        unlocked = 0;
        _;
        unlocked = 1;
    }

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

    function setMintFee(uint256 fee) external override {
        require(msg.sender == factory, 'TP00');
        require(fee != mintFee, 'TP01');
        mintFee = fee;
        emit SetMintFee(fee);
    }

    function setBurnFee(uint256 fee) external override {
        require(msg.sender == factory, 'TP00');
        require(fee != burnFee, 'TP01');
        burnFee = fee;
        emit SetBurnFee(fee);
    }

    function setSwapFee(uint256 fee) external override {
        require(msg.sender == factory, 'TP00');
        require(fee != swapFee, 'TP01');
        swapFee = fee;
        emit SetSwapFee(fee);
    }

    function setOracle(address _oracle) external override {
        require(msg.sender == factory, 'TP00');
        require(_oracle != oracle, 'TP01');
        require(_oracle != address(0), 'TP02');
        require(isContract(_oracle), 'TP1D');
        oracle = _oracle;
        emit SetOracle(_oracle);
    }

    function setTrader(address _trader) external override {
        require(msg.sender == factory, 'TP00');
        require(_trader != trader, 'TP01');
        // Allow trader to be set as address(0) to disable interaction
        trader = _trader;
        emit SetTrader(_trader);
    }

    function collect(address to) external override lock {
        require(msg.sender == factory, 'TP00');
        require(to != address(0), 'TP02');
        (uint256 fee0, uint256 fee1) = getFees();
        if (fee0 > 0) _safeTransfer(token0, to, fee0);
        if (fee1 > 0) _safeTransfer(token1, to, fee1);
        setFees(0, 0);
        _sync();
    }

    function _safeTransfer(
        address token,
        address to,
        uint256 value
    ) private {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TP05');
    }

    function canTrade(address user) private view returns (bool) {
        return user == trader || user == factory;
    }

    constructor() {
        factory = msg.sender;
    }

    // called once by the factory at time of deployment
    function initialize(
        address _token0,
        address _token1,
        address _oracle,
        address _trader
    ) external override {
        require(msg.sender == factory, 'TP00');
        require(_oracle != address(0), 'TP02');
        require(isContract(_oracle), 'TP1D');
        require(isContract(_token0) && isContract(_token1), 'TP10');
        token0 = _token0;
        token1 = _token1;
        oracle = _oracle;
        trader = _trader;
    }

    // this low-level function should be called from a contract which performs important safety checks
    function mint(address to) external override lock returns (uint256 liquidityOut) {
        require(canTrade(msg.sender), 'TP0C');
        require(to != address(0), 'TP02');
        (uint112 reserve0, uint112 reserve1) = getReserves();
        (uint256 balance0, uint256 balance1) = getBalances(token0, token1);
        uint256 amount0In = balance0.sub(reserve0);
        uint256 amount1In = balance1.sub(reserve1);

        uint256 _totalSupply = totalSupply; // gas savings
        if (_totalSupply == 0) {
            liquidityOut = Math.sqrt(amount0In.mul(amount1In)).sub(MINIMUM_LIQUIDITY);
            _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
        } else {
            liquidityOut = Math.min(amount0In.mul(_totalSupply) / reserve0, amount1In.mul(_totalSupply) / reserve1);
        }

        require(liquidityOut > 0, 'TP38');
        if (mintFee > 0) {
            uint256 fee = liquidityOut.mul(mintFee).div(PRECISION);
            liquidityOut = liquidityOut.sub(fee);
            _mint(factory, fee);
        }
        _mint(to, liquidityOut);

        setReserves(balance0, balance1);

        emit Mint(msg.sender, amount0In, amount1In, liquidityOut, to);
    }

    // this low-level function should be called from a contract which performs important safety checks
    function burn(address to) external override lock returns (uint256 amount0Out, uint256 amount1Out) {
        require(canTrade(msg.sender), 'TP0C');
        require(to != address(0), 'TP02');
        uint256 _totalSupply = totalSupply; // gas savings
        require(_totalSupply > 0, 'TP36');
        address _token0 = token0; // gas savings
        address _token1 = token1; // gas savings
        (uint256 balance0, uint256 balance1) = getBalances(token0, token1);
        uint256 liquidityIn = balanceOf[address(this)];

        if (msg.sender != factory && burnFee > 0) {
            uint256 fee = liquidityIn.mul(burnFee).div(PRECISION);
            liquidityIn = liquidityIn.sub(fee);
            _transfer(address(this), factory, fee);
        }
        _burn(address(this), liquidityIn);

        amount0Out = liquidityIn.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution
        amount1Out = liquidityIn.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution
        require(amount0Out > 0 && amount1Out > 0, 'TP39');

        _safeTransfer(_token0, to, amount0Out);
        _safeTransfer(_token1, to, amount1Out);

        (balance0, balance1) = getBalances(token0, token1);
        setReserves(balance0, balance1);

        emit Burn(msg.sender, amount0Out, amount1Out, liquidityIn, to);
    }

    // this low-level function should be called from a contract which performs important safety checks
    function swap(
        uint256 amount0Out,
        uint256 amount1Out,
        address to,
        bytes calldata data
    ) external override lock {
        require(canTrade(msg.sender), 'TP0C');
        require(to != address(0), 'TP02');
        require((amount0Out > 0 && amount1Out == 0) || (amount1Out > 0 && amount0Out == 0), 'TP31');
        (uint112 _reserve0, uint112 _reserve1) = getReserves();
        require(amount0Out < _reserve0 && amount1Out < _reserve1, 'TP07');

        {
            // scope for _token{0,1}, avoids stack too deep errors
            address _token0 = token0;
            address _token1 = token1;
            require(to != _token0 && to != _token1, 'TP2D');
            if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
            if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
        }
        (uint256 balance0, uint256 balance1) = getBalances(token0, token1);

        if (amount0Out > 0) {
            // trading token1 for token0
            require(balance1 > _reserve1, 'TP08');
            uint256 amount1In = balance1 - _reserve1;

            emit Swap(msg.sender, 0, amount1In, amount0Out, 0, to);

            uint256 fee1 = amount1In.mul(swapFee).div(PRECISION);
            uint256 balance1After = balance1.sub(fee1);
            uint256 balance0After = ITwapOracle(oracle).tradeY(balance1After, _reserve0, _reserve1, data);
            require(balance0 >= balance0After, 'TP2E');
            uint256 fee0 = balance0.sub(balance0After);
            addFees(fee0, fee1);
            setReserves(balance0After, balance1After);
        } else {
            // trading token0 for token1
            require(balance0 > _reserve0, 'TP08');
            uint256 amount0In = balance0 - _reserve0;

            emit Swap(msg.sender, amount0In, 0, 0, amount1Out, to);

            uint256 fee0 = amount0In.mul(swapFee).div(PRECISION);
            uint256 balance0After = balance0.sub(fee0);
            uint256 balance1After = ITwapOracle(oracle).tradeX(balance0After, _reserve0, _reserve1, data);
            require(balance1 >= balance1After, 'TP2E');
            uint256 fee1 = balance1.sub(balance1After);
            addFees(fee0, fee1);
            setReserves(balance0After, balance1After);
        }
    }

    function sync() external override lock {
        require(canTrade(msg.sender), 'TP0C');
        _sync();
    }

    // force reserves to match balances
    function _sync() internal {
        syncReserves(token0, token1);
        uint256 tokens = balanceOf[address(this)];
        if (tokens > 0) {
            _transfer(address(this), factory, tokens);
        }
    }

    function getSwapAmount0In(uint256 amount1Out, bytes calldata data)
        public
        view
        override
        returns (uint256 swapAmount0In)
    {
        (uint112 reserve0, uint112 reserve1) = getReserves();
        uint256 balance1After = uint256(reserve1).sub(amount1Out);
        uint256 balance0After = ITwapOracle(oracle).tradeY(balance1After, reserve0, reserve1, data);
        return balance0After.sub(uint256(reserve0)).mul(PRECISION).ceil_div(PRECISION.sub(swapFee));
    }

    function getSwapAmount1In(uint256 amount0Out, bytes calldata data)
        public
        view
        override
        returns (uint256 swapAmount1In)
    {
        (uint112 reserve0, uint112 reserve1) = getReserves();
        uint256 balance0After = uint256(reserve0).sub(amount0Out);
        uint256 balance1After = ITwapOracle(oracle).tradeX(balance0After, reserve0, reserve1, data);
        return balance1After.add(1).sub(uint256(reserve1)).mul(PRECISION).ceil_div(PRECISION.sub(swapFee));
    }

    function getSwapAmount0Out(uint256 amount1In, bytes calldata data)
        public
        view
        override
        returns (uint256 swapAmount0Out)
    {
        (uint112 reserve0, uint112 reserve1) = getReserves();
        uint256 fee = amount1In.mul(swapFee).div(PRECISION);
        uint256 balance0After = ITwapOracle(oracle).tradeY(
            uint256(reserve1).add(amount1In).sub(fee),
            reserve0,
            reserve1,
            data
        );
        return uint256(reserve0).sub(balance0After);
    }

    function getSwapAmount1Out(uint256 amount0In, bytes calldata data)
        public
        view
        override
        returns (uint256 swapAmount1Out)
    {
        (uint112 reserve0, uint112 reserve1) = getReserves();
        uint256 fee = amount0In.mul(swapFee).div(PRECISION);
        uint256 balance1After = ITwapOracle(oracle).tradeX(
            uint256(reserve0).add(amount0In).sub(fee),
            reserve0,
            reserve1,
            data
        );
        return uint256(reserve1).sub(balance1After);
    }

    function getDepositAmount0In(uint256 amount0, bytes calldata data) external view override returns (uint256) {
        (uint112 reserve0, uint112 reserve1) = getReserves();
        return ITwapOracle(oracle).depositTradeXIn(amount0, reserve0, reserve1, data);
    }

    function getDepositAmount1In(uint256 amount1, bytes calldata data) external view override returns (uint256) {
        (uint112 reserve0, uint112 reserve1) = getReserves();
        return ITwapOracle(oracle).depositTradeYIn(amount1, reserve0, reserve1, data);
    }
}

File 22 of 25 : Reserves.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

import '../interfaces/IReserves.sol';
import '../interfaces/IERC20.sol';
import '../libraries/SafeMath.sol';

contract Reserves is IReserves {
    using SafeMath for uint256;

    uint112 private reserve0;
    uint112 private reserve1;

    uint112 private fee0;
    uint112 private fee1;

    function getReserves() public view override returns (uint112, uint112) {
        return (reserve0, reserve1);
    }

    function setReserves(uint256 balance0MinusFee, uint256 balance1MinusFee) internal {
        require(balance0MinusFee != 0 && balance1MinusFee != 0, 'RS09');
        reserve0 = balance0MinusFee.toUint112();
        reserve1 = balance1MinusFee.toUint112();
    }

    function syncReserves(address token0, address token1) internal {
        uint256 balance0 = IERC20(token0).balanceOf(address(this));
        uint256 balance1 = IERC20(token1).balanceOf(address(this));

        uint256 oldBalance0 = uint256(reserve0) + fee0;
        uint256 oldBalance1 = uint256(reserve1) + fee1;

        if (balance0 != oldBalance0 || balance1 != oldBalance1) {
            if (oldBalance0 != 0) {
                fee0 = (balance0.mul(fee0).div(oldBalance0)).toUint112();
            }
            if (oldBalance1 != 0) {
                fee1 = (balance1.mul(fee1).div(oldBalance1)).toUint112();
            }

            setReserves(balance0.sub(fee0), balance1.sub(fee1));
        }
    }

    function getFees() public view override returns (uint256, uint256) {
        return (fee0, fee1);
    }

    function addFees(uint256 _fee0, uint256 _fee1) internal {
        setFees(_fee0.add(fee0), _fee1.add(fee1));
    }

    function setFees(uint256 _fee0, uint256 _fee1) internal {
        fee0 = _fee0.toUint112();
        fee1 = _fee1.toUint112();
    }

    function getBalances(address token0, address token1) internal returns (uint256, uint256) {
        uint256 balance0 = IERC20(token0).balanceOf(address(this));
        uint256 balance1 = IERC20(token1).balanceOf(address(this));
        if (fee0 > balance0) {
            fee0 = uint112(balance0);
        }
        if (fee1 > balance1) {
            fee1 = uint112(balance1);
        }
        return (balance0.sub(fee0), balance1.sub(fee1));
    }
}

File 23 of 25 : TwapLPToken.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

import './libraries/AbstractERC20.sol';

contract TwapLPToken is AbstractERC20 {
    constructor() {
        name = 'Twap LP';
        symbol = 'TWAP-LP';
        decimals = 18;
    }
}

File 24 of 25 : AbstractERC20.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

import '../interfaces/ITwapERC20.sol';
import './SafeMath.sol';

abstract contract AbstractERC20 is ITwapERC20 {
    using SafeMath for uint256;

    string public override name;
    string public override symbol;
    uint8 public override decimals;

    uint256 public override totalSupply;
    mapping(address => uint256) public override balanceOf;
    mapping(address => mapping(address => uint256)) public override allowance;

    bytes32 public constant DOMAIN_TYPEHASH =
        keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)');
    // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    bytes32 public constant override PERMIT_TYPEHASH =
        0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
    mapping(address => uint256) public override nonces;

    function _mint(address to, uint256 value) internal {
        totalSupply = totalSupply.add(value);
        balanceOf[to] = balanceOf[to].add(value);
        emit Transfer(address(0), to, value);
    }

    function _burn(address from, uint256 value) internal {
        balanceOf[from] = balanceOf[from].sub(value);
        totalSupply = totalSupply.sub(value);
        emit Transfer(from, address(0), value);
    }

    function _approve(
        address owner,
        address spender,
        uint256 value
    ) internal {
        allowance[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    function _transfer(
        address from,
        address to,
        uint256 value
    ) internal {
        balanceOf[from] = balanceOf[from].sub(value);
        balanceOf[to] = balanceOf[to].add(value);
        emit Transfer(from, to, value);
    }

    function approve(address spender, uint256 value) external override returns (bool) {
        _approve(msg.sender, spender, value);
        return true;
    }

    function increaseAllowance(address spender, uint256 addedValue) external override returns (bool) {
        _approve(msg.sender, spender, allowance[msg.sender][spender].add(addedValue));
        return true;
    }

    function decreaseAllowance(address spender, uint256 subtractedValue) external override returns (bool) {
        uint256 currentAllowance = allowance[msg.sender][spender];
        require(currentAllowance >= subtractedValue, 'TA48');
        _approve(msg.sender, spender, currentAllowance.sub(subtractedValue));
        return true;
    }

    function transfer(address to, uint256 value) external override returns (bool) {
        _transfer(msg.sender, to, value);
        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external override returns (bool) {
        if (allowance[from][msg.sender] != uint256(-1)) {
            allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
        }
        _transfer(from, to, value);
        return true;
    }

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external override {
        require(deadline >= block.timestamp, 'TA04');
        bytes32 digest = keccak256(
            abi.encodePacked(
                '\x19\x01',
                getDomainSeparator(),
                keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
            )
        );
        address recoveredAddress = ecrecover(digest, v, r, s);
        require(recoveredAddress != address(0) && recoveredAddress == owner, 'TA2F');
        _approve(owner, spender, value);
    }

    function getDomainSeparator() public view returns (bytes32) {
        uint256 chainId;
        assembly {
            chainId := chainid()
        }
        return
            keccak256(
                abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), keccak256(bytes('1')), chainId, address(this))
            );
    }
}

File 25 of 25 : TwapFactory.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9

pragma solidity 0.7.6;

import './interfaces/ITwapFactory.sol';
import './TwapPair.sol';

contract TwapFactory is ITwapFactory {
    mapping(address => mapping(address => address)) public override getPair;
    address[] public override allPairs;
    address public override owner;

    constructor() {
        owner = msg.sender;

        emit OwnerSet(msg.sender);
    }

    function allPairsLength() external view override returns (uint256) {
        return allPairs.length;
    }

    function createPair(
        address tokenA,
        address tokenB,
        address oracle,
        address trader
    ) external override returns (address pair) {
        require(msg.sender == owner, 'TF00');
        require(tokenA != tokenB, 'TF3B');
        (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        require(token0 != address(0), 'TF02');
        require(getPair[token0][token1] == address(0), 'TF18'); // single check is sufficient
        bytes memory bytecode = type(TwapPair).creationCode;
        bytes32 salt = keccak256(abi.encodePacked(token0, token1));
        assembly {
            pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
        }
        ITwapPair(pair).initialize(token0, token1, oracle, trader);
        getPair[token0][token1] = pair;
        getPair[token1][token0] = pair; // populate mapping in the reverse direction
        allPairs.push(pair);
        emit PairCreated(token0, token1, pair, allPairs.length);
    }

    function setOwner(address _owner) external override {
        require(msg.sender == owner, 'TF00');
        require(_owner != owner, 'TF01');
        require(_owner != address(0), 'TF02');
        owner = _owner;
        emit OwnerSet(_owner);
    }

    function setMintFee(
        address tokenA,
        address tokenB,
        uint256 fee
    ) external override {
        require(msg.sender == owner, 'TF00');
        _getPair(tokenA, tokenB).setMintFee(fee);
    }

    function setBurnFee(
        address tokenA,
        address tokenB,
        uint256 fee
    ) external override {
        require(msg.sender == owner, 'TF00');
        _getPair(tokenA, tokenB).setBurnFee(fee);
    }

    function setSwapFee(
        address tokenA,
        address tokenB,
        uint256 fee
    ) external override {
        require(msg.sender == owner, 'TF00');
        _getPair(tokenA, tokenB).setSwapFee(fee);
    }

    function setOracle(
        address tokenA,
        address tokenB,
        address oracle
    ) external override {
        require(msg.sender == owner, 'TF00');
        _getPair(tokenA, tokenB).setOracle(oracle);
    }

    function setTrader(
        address tokenA,
        address tokenB,
        address trader
    ) external override {
        require(msg.sender == owner, 'TF00');
        _getPair(tokenA, tokenB).setTrader(trader);
    }

    function collect(
        address tokenA,
        address tokenB,
        address to
    ) external override {
        require(msg.sender == owner, 'TF00');
        _getPair(tokenA, tokenB).collect(to);
    }

    function withdraw(
        address tokenA,
        address tokenB,
        uint256 amount,
        address to
    ) external override {
        require(msg.sender == owner, 'TF00');
        ITwapPair pair = _getPair(tokenA, tokenB);
        pair.transfer(address(pair), amount);
        pair.burn(to);
    }

    function _getPair(address tokenA, address tokenB) internal view returns (ITwapPair pair) {
        pair = ITwapPair(getPair[tokenA][tokenB]);
        require(address(pair) != address(0), 'TF19');
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {
    "contracts/libraries/AddLiquidity.sol": {
      "AddLiquidity": "0xb291730099d3ac9975abd4003ba3bd47401fd2fd"
    },
    "contracts/libraries/Orders.sol": {
      "Orders": "0x6336788a85f54d8856782d58c1ca63c7d3844531"
    },
    "contracts/libraries/TokenShares.sol": {
      "TokenShares": "0xb28c804e3dacff80701bbbafd106dbfb416a5168"
    },
    "contracts/libraries/WithdrawHelper.sol": {
      "WithdrawHelper": "0x6195015b38773f468dd43620dd5a64e9bb63c2e3"
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_bot","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"bot","type":"address"},{"indexed":false,"internalType":"bool","name":"isBot","type":"bool"}],"name":"BotSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"DelaySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"EthRefund","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"n","type":"uint256"}],"name":"Execute","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"gasPriceInertia","type":"uint256"}],"name":"GasPriceInertiaSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxGasLimit","type":"uint256"}],"name":"MaxGasLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxGasPriceImpact","type":"uint256"}],"name":"MaxGasPriceImpactSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"indexed":false,"internalType":"bool","name":"disabled","type":"bool"}],"name":"OrderDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"gasSpent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ethRefunded","type":"uint256"}],"name":"OrderExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"OwnerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"RefundFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"gasCost","type":"uint256"}],"name":"TransferGasCostSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"UnwrapFailed","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"bool","name":"inverse","type":"bool"},{"internalType":"uint256","name":"shareInMax","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.BuyOrder","name":"buyOrder","type":"tuple"}],"name":"_executeBuy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"uint256","name":"share0","type":"uint256"},{"internalType":"uint256","name":"share1","type":"uint256"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.DepositOrder","name":"depositOrder","type":"tuple"}],"name":"_executeDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"bool","name":"inverse","type":"bool"},{"internalType":"uint256","name":"shareIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.SellOrder","name":"sellOrder","type":"tuple"}],"name":"_executeSell","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"}],"internalType":"struct Orders.WithdrawOrder","name":"withdrawOrder","type":"tuple"}],"name":"_executeWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"name":"_refundLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"share","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"}],"name":"_refundToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"uint256","name":"share0","type":"uint256"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"share1","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"}],"name":"_refundTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"bool","name":"wrapUnwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.BuyParams","name":"buyParams","type":"tuple"}],"name":"buy","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delay","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"wrap","type":"bool"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.DepositParams","name":"depositParams","type":"tuple"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"n","type":"uint256"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasPriceInertia","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getBuyDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getBuyOrder","outputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"bool","name":"inverse","type":"bool"},{"internalType":"uint256","name":"shareInMax","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.BuyOrder","name":"order","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getDepositDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getDepositOrder","outputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"uint256","name":"share0","type":"uint256"},{"internalType":"uint256","name":"share1","type":"uint256"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.DepositOrder","name":"order","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getOrder","outputs":[{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getOrderStatus","outputs":[{"internalType":"enum Orders.OrderStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getSellDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getSellOrder","outputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"bool","name":"inverse","type":"bool"},{"internalType":"uint256","name":"shareIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.SellOrder","name":"order","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTransferGasCost","outputs":[{"internalType":"uint256","name":"gasCost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getWithdrawDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getWithdrawOrder","outputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"}],"internalType":"struct Orders.WithdrawOrder","name":"order","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isBot","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"isOrderCanceled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastProcessedOrderId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxGasLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxGasPriceImpact","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newestOrderId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"retryRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"wrapUnwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.SellParams","name":"sellParams","type":"tuple"}],"name":"sell","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_bot","type":"address"},{"internalType":"bool","name":"_isBot","type":"bool"}],"name":"setBot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_delay","type":"uint32"}],"name":"setDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasPriceInertia","type":"uint256"}],"name":"setGasPriceInertia","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxGasLimit","type":"uint256"}],"name":"setMaxGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxGasPriceImpact","type":"uint256"}],"name":"setMaxGasPriceImpact","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"disabled","type":"bool"}],"name":"setOrderDisabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"gasCost","type":"uint256"}],"name":"setTransferGasCost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.WithdrawParams","name":"withdrawParams","type":"tuple"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]

608060405260016011553480156200001657600080fd5b5060405162005fc938038062005fc98339810160408190526200003991620001bd565b600480546001600160a01b038086166001600160a01b031992831617909255600f80549091163317905581166000908152601060205260409020805460ff19166001179055620f42403a063a03600655620000a2600d836200017b602090811b6200296d17901c565b6000805463ffffffff1916610708178155624c4b406005556301312d00600755620f424060085560405163b2456a0760e01b8152736336788a85f54d8856782d58c1ca63c7d38445319163b2456a07916200010791908190612710906004016200021a565b60006040518083038186803b1580156200012057600080fd5b505af415801562000135573d6000803e3d6000fd5b505050507f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe2336040516200016a919062000206565b60405180910390a150505062000239565b60019190910180546001600160a01b0319166001600160a01b03909216919091179055565b80516001600160a01b0381168114620001b857600080fd5b919050565b600080600060608486031215620001d2578283fd5b620001dd84620001a0565b9250620001ed60208501620001a0565b9150620001fd60408501620001a0565b90509250925092565b6001600160a01b0391909116815260200190565b9283526001600160a01b03919091166020830152604082015260600190565b615d8080620002496000396000f3fe6080604052600436106102815760003560e01c806377632ec21161014f578063be581304116100c1578063e30a49931161007a578063e30a49931461078d578063e5b1be65146107a2578063e5e7988e146107c2578063e6a0cc94146107e2578063fe0d94c1146107f7578063fe173b971461081757610288565b8063be581304146106ca578063bf6b874e146106ea578063c45a01551461070a578063c9cd97601461071f578063d09ef2411461073f578063d22e92421461076d57610288565b80639d08ebb5116101135780639d08ebb5146106245780639da92cfa14610637578063af482b5814610657578063b1af1bda14610677578063b32ac93614610697578063ba4d5312146106b757610288565b806377632ec21461058f5780637f6a1caf146105af5780638da5cb5b146105cf57806394531713146105e45780639718f6271461060457610288565b80633fc8cef3116101f3578063576b332b116101ac578063576b332b146104fb57806357a62a4f1461050e5780635e45da2314610523578063690910c4146105385780636a42b8f8146105585780636de3c67c1461057a57610288565b80633fc8cef31461041f57806345fa8aae146104415780634c0160161461046e5780635051349a1461048e578063514fcac7146104ae57806354df6d74146104ce57610288565b806320a68fab1161024557806320a68fab14610345578063342aa8b514610372578063390ce0d3146103925780633bbac579146103bf5780633c763c17146103df5780633ed76f17146103ff57610288565b80630b65604d1461028d57806310348665146102af57806313af4035146102cf5780631776834a146102ef57806317818a5c1461030f57610288565b3661028857005b600080fd5b34801561029957600080fd5b506102ad6102a8366004614ff5565b61082c565b005b3480156102bb57600080fd5b506102ad6102ca36600461536b565b610c10565b3480156102db57600080fd5b506102ad6102ea366004614d27565b610cb5565b3480156102fb57600080fd5b506102ad61030a366004615318565b610d7e565b34801561031b57600080fd5b5061032f61032a366004615318565b610e15565b60405161033c9190615ba0565b60405180910390f35b34801561035157600080fd5b50610365610360366004614d27565b610eb0565b60405161033c9190615692565b34801561037e57600080fd5b506102ad61038d366004614eac565b610f3c565b34801561039e57600080fd5b506103b26103ad366004615318565b611007565b60405161033c919061587d565b3480156103cb57600080fd5b506103656103da366004614d27565b61109a565b3480156103eb57600080fd5b506102ad6103fa366004614ff5565b6110af565b34801561040b57600080fd5b506102ad61041a366004614deb565b611482565b34801561042b57600080fd5b506104346114a2565b60405161033c919061552d565b34801561044d57600080fd5b5061046161045c366004615318565b6114b1565b60405161033c91906156c2565b34801561047a57600080fd5b50610365610489366004614d27565b61153d565b6104a161049c36600461502d565b611579565b60405161033c91906158ab565b3480156104ba57600080fd5b506102ad6104c9366004615318565b61161d565b3480156104da57600080fd5b506104ee6104e9366004615318565b611807565b60405161033c9190615ada565b6104a1610509366004615306565b61189a565b34801561051a57600080fd5b506104a16118fd565b34801561052f57600080fd5b506104a1611903565b34801561054457600080fd5b506102ad6105533660046151f0565b611909565b34801561056457600080fd5b5061056d611c97565b60405161033c9190615c67565b34801561058657600080fd5b506104a1611ca3565b34801561059b57600080fd5b506103656105aa366004615318565b611ca9565b3480156105bb57600080fd5b506102ad6105ca366004614ee4565b611cbe565b3480156105db57600080fd5b50610434611d52565b3480156105f057600080fd5b506102ad6105ff366004615318565b611d61565b34801561061057600080fd5b506104a161061f366004614d27565b611dc5565b6104a16106323660046151de565b611de0565b34801561064357600080fd5b506102ad610652366004615049565b611e46565b34801561066357600080fd5b50610365610672366004614d27565b6120df565b34801561068357600080fd5b506103b2610692366004615318565b61211b565b3480156106a357600080fd5b506102ad6106b2366004615318565b61215d565b6104a16106c536600461502d565b6121c1565b3480156106d657600080fd5b506102ad6106e5366004615318565b612227565b3480156106f657600080fd5b506104a1610705366004614d27565b6122f1565b34801561071657600080fd5b5061043461230c565b34801561072b57600080fd5b506102ad61073a366004614dab565b61231b565b34801561074b57600080fd5b5061075f61075a366004615318565b61234a565b60405161033c9291906156d6565b34801561077957600080fd5b506102ad610788366004614f23565b6123e0565b34801561079957600080fd5b506104a1612472565b3480156107ae57600080fd5b506102ad6107bd366004614e5a565b612478565b3480156107ce57600080fd5b506103656107dd366004614d27565b61266e565b3480156107ee57600080fd5b506104a16126aa565b34801561080357600080fd5b506102ad610812366004615318565b6126b0565b34801561082357600080fd5b506104a1612967565b3330146108545760405162461bcd60e51b815260040161084b9061578d565b60405180910390fd5b426202a30082610100015163ffffffff160110156108845760405162461bcd60e51b815260040161084b906157e7565b600080600061089b84600001518560200151612992565b9250925092506000600d73b28c804e3dacff80701bbbafd106dbfb416a5168636c5d9cf090918588604001516040518463ffffffff1660e01b81526004016108e59392919061588c565b60206040518083038186803b1580156108fd57600080fd5b505af4158015610911573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109359190615330565b90506000849050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561097757600080fd5b505af115801561098b573d6000803e3d6000fd5b5050505060006109a686886101200151896101400151612a52565b905060008760200151610a3657604051632b9b015d60e01b81526001600160a01b03841690632b9b015d906109e19087908690600401615c17565b60206040518083038186803b1580156109f957600080fd5b505afa158015610a0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a319190615330565b610ab4565b6040516302b97d6d60e21b81526001600160a01b03841690630ae5f5b490610a649087908690600401615c17565b60206040518083038186803b158015610a7c57600080fd5b505afa158015610a90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab49190615330565b90508760600151811015610ada5760405162461bcd60e51b815260040161084b9061576f565b6000808960200151610aee57600083610af2565b8260005b91509150610b01888a88612b70565b600e546001600160a01b038881169116148015610b1f575089608001515b15610b9b5760405163022c0d9f60e01b81526001600160a01b0386169063022c0d9f90610b56908590859030908a90600401615c30565b600060405180830381600087803b158015610b7057600080fd5b505af1158015610b84573d6000803e3d6000fd5b50505050610b968a60a0015184612cbb565b610c04565b60a08a015160405163022c0d9f60e01b81526001600160a01b0387169163022c0d9f91610bd19186918691908a90600401615c30565b600060405180830381600087803b158015610beb57600080fd5b505af1158015610bff573d6000803e3d6000fd5b505050505b50505050505050505050565b600f546001600160a01b03163314610c3a5760405162461bcd60e51b815260040161084b9061578d565b60005463ffffffff82811691161415610c655760405162461bcd60e51b815260040161084b906157ab565b6000805463ffffffff191663ffffffff83161790556040517f63e09f16584208fba1fc7ff64c62b00f07bec177c0d97ca6689891b1e77a35c790610caa908390615c67565b60405180910390a150565b600f546001600160a01b03163314610cdf5760405162461bcd60e51b815260040161084b9061578d565b600f546001600160a01b0382811691161415610d0d5760405162461bcd60e51b815260040161084b906157ab565b6001600160a01b038116610d335760405162461bcd60e51b815260040161084b90615823565b600f80546001600160a01b0319166001600160a01b0383161790556040517f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe290610caa90839061552d565b600f546001600160a01b03163314610da85760405162461bcd60e51b815260040161084b9061578d565b604051636702eca360e01b8152736336788a85f54d8856782d58c1ca63c7d384453190636702eca390610de2906000908590600401615ab8565b60006040518083038186803b158015610dfa57600080fd5b505af4158015610e0e573d6000803e3d6000fd5b5050505050565b610e1d614a1d565b604051634ce4436960e11b8152736336788a85f54d8856782d58c1ca63c7d3844531906399c886d290610e57906000908690600401615ab8565b6101206040518083038186803b158015610e7057600080fd5b505af4158015610e84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea8919061527b565b90505b919050565b604051631ae4448160e31b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063d722240890610eec90849086906004016158b4565b60206040518083038186803b158015610f0457600080fd5b505af4158015610f18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190614f4e565b600f546001600160a01b03163314610f665760405162461bcd60e51b815260040161084b9061578d565b6001600160a01b03821660009081526010602052604090205460ff1615158115151415610fa55760405162461bcd60e51b815260040161084b906157ab565b6001600160a01b03821660009081526010602052604090819020805460ff1916831515179055517f70af441dbb427737e6a5ef2cf5b664321011765ce1d19ce4a69cd024e69d4f2f90610ffb9084908490615677565b60405180910390a15050565b61100f614a80565b60405163ac1ecdb360e01b8152736336788a85f54d8856782d58c1ca63c7d38445319063ac1ecdb390611049906000908690600401615ab8565b6101606040518083038186803b15801561106257600080fd5b505af4158015611076573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190615011565b60106020526000908152604090205460ff1681565b3330146110ce5760405162461bcd60e51b815260040161084b9061578d565b426202a30082610100015163ffffffff160110156110fe5760405162461bcd60e51b815260040161084b906157e7565b600080600061111584600001518560200151612992565b9250925092506000600d73b28c804e3dacff80701bbbafd106dbfb416a5168636c5d9cf090918588604001516040518463ffffffff1660e01b815260040161115f9392919061588c565b60206040518083038186803b15801561117757600080fd5b505af415801561118b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111af9190615330565b90506000849050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156111f157600080fd5b505af1158015611205573d6000803e3d6000fd5b50505050600061122086886101200151896101400151612a52565b9050600087602001516112b457606088015160405163c7481b8f60e01b81526001600160a01b0385169163c7481b8f9161125f91908690600401615c17565b60206040518083038186803b15801561127757600080fd5b505afa15801561128b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112af9190615330565b611336565b606088015160405163d6945d8960e01b81526001600160a01b0385169163d6945d89916112e691908690600401615c17565b60206040518083038186803b1580156112fe57600080fd5b505afa158015611312573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113369190615330565b9050808410156113585760405162461bcd60e51b815260040161084b90615841565b808411156113ba57600e546001600160a01b03878116911614801561137e575087608001515b156113a05760a088015161139b906113968684612ddb565b612cbb565b6113ba565b60a08801516113ba9087906113b58785612ddb565b612b70565b60008089602001516113d25760008a606001516113da565b896060015160005b915091506113e9888a85612b70565b600e546001600160a01b038881169116148015611407575089608001515b15610b9b5760405163022c0d9f60e01b81526001600160a01b0386169063022c0d9f9061143e908590859030908a90600401615c30565b600060405180830381600087803b15801561145857600080fd5b505af115801561146c573d6000803e3d6000fd5b50505050610b968a60a001518b60600151612cbb565b61148e85878684612478565b61149a83878484612478565b505050505050565b600e546001600160a01b031690565b604051634dc1ffe760e11b8152600090736336788a85f54d8856782d58c1ca63c7d384453190639b83ffce906114ed9084908690600401615ab8565b60206040518083038186803b15801561150557600080fd5b505af4158015611519573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190614fa8565b604051634d95367160e11b8152600090736336788a85f54d8856782d58c1ca63c7d384453190639b2a6ce290610eec90849086906004016158b4565b600060115460011461159d5760405162461bcd60e51b815260040161084b906156f7565b6000601181905560405162c44ff160e31b8152736336788a85f54d8856782d58c1ca63c7d3844531916306227f88916115de91908690600d906004016158ff565b60006040518083038186803b1580156115f657600080fd5b505af415801561160a573d6000803e3d6000fd5b5050600154925050506001601155919050565b60115460011461163f5760405162461bcd60e51b815260040161084b906156f7565b60006011556002604051634dc1ffe760e11b8152736336788a85f54d8856782d58c1ca63c7d384453190639b83ffce90611680906000908690600401615ab8565b60206040518083038186803b15801561169857600080fd5b505af41580156116ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d09190614fa8565b60058111156116db57fe5b146116f85760405162461bcd60e51b815260040161084b90615805565b60405163317e626f60e21b81526000908190736336788a85f54d8856782d58c1ca63c7d38445319063c5f989bc906117369084908790600401615ab8565b604080518083038186803b15801561174d57600080fd5b505af4158015611761573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117859190614fc7565b60005491935063ffffffff908116925042916117b59162015180916117af918691811690612ddb16565b90612e0b565b106117d25760405162461bcd60e51b815260040161084b90615715565b6000838152600b60205260409020805460ff191660019081179091556117fd90839083908690612e52565b5050600160115550565b61180f614adc565b60405163117d7ab160e01b8152736336788a85f54d8856782d58c1ca63c7d38445319063117d7ab190611849906000908690600401615ab8565b6101a06040518083038186803b15801561186257600080fd5b505af4158015611876573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190615119565b60006011546001146118be5760405162461bcd60e51b815260040161084b906156f7565b60006011819055604051636587992160e01b8152736336788a85f54d8856782d58c1ca63c7d3844531916365879921916115de91908690600401615a0d565b60085490565b60055490565b3330146119285760405162461bcd60e51b815260040161084b9061578d565b426202a30082610100015163ffffffff160110156119585760405162461bcd60e51b815260040161084b906157e7565b8051604051630270f5c360e51b815260009182918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb8609161199991859190600401615ac6565b60606040518083038186803b1580156119b157600080fd5b505af41580156119c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e99190614d5f565b925092509250826001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a2a57600080fd5b505af1158015611a3e573d6000803e3d6000fd5b50505050611a5183848660200151612b70565b6080840151600090819081908015611a8d5750600e546001600160a01b0386811691161480611a8d5750600e546001600160a01b038581169116145b15611bd357600e5460a08801516000808052600a602052600080516020615d2b8339815191525460405163cf58beed60e01b81529193736195015b38773f468dd43620dd5a64e9bb63c2e39363cf58beed93611aff938c938c938f936001600160a01b0390921692909160040161555a565b60806040518083038186803b158015611b1757600080fd5b505af4158015611b2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b4f9190614f6a565b91965094509250905080611bcd5760a088015160405163032b310f60e51b815273b28c804e3dacff80701bbbafd106dbfb416a51689163656621e091611b9c91600d91899060040161588c565b60006040518083038186803b158015611bb457600080fd5b505af4158015611bc8573d6000803e3d6000fd5b505050505b50611c5a565b60a087015160405163226bf2d160e21b81526001600160a01b038816916389afcb4491611c03919060040161552d565b6040805180830381600087803b158015611c1c57600080fd5b505af1158015611c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c549190615348565b90925090505b86604001518210158015611c72575086606001518110155b611c8e5760405162461bcd60e51b815260040161084b90615751565b50505050505050565b60005463ffffffff1690565b60075490565b6000908152600b602052604090205460ff1690565b600f546001600160a01b03163314611ce85760405162461bcd60e51b815260040161084b9061578d565b60405163146bce4f60e31b8152736336788a85f54d8856782d58c1ca63c7d38445319063a35e727890611d26906000908790879087906004016158cb565b60006040518083038186803b158015611d3e57600080fd5b505af4158015611c8e573d6000803e3d6000fd5b600f546001600160a01b031681565b600f546001600160a01b03163314611d8b5760405162461bcd60e51b815260040161084b9061578d565b604051630fd1437d60e11b8152736336788a85f54d8856782d58c1ca63c7d384453190631fa286fa90610de2906000908590600401615ab8565b6001600160a01b03166000908152600a602052604090205490565b6000601154600114611e045760405162461bcd60e51b815260040161084b906156f7565b60006011819055604051638f0e6bef60e01b8152736336788a85f54d8856782d58c1ca63c7d384453191638f0e6bef916115de91908690600d90600401615923565b333014611e655760405162461bcd60e51b815260040161084b9061578d565b426202a30082610140015163ffffffff16011015611e955760405162461bcd60e51b815260040161084b906157e7565b6000806000806000611ea6866135e8565b945094509450945094508560c0015115612022578115611f705773b291730099d3ac9975abd4003ba3bd47401fd2fd6388aae0878686858a60600151611ef78b8d61016001518e6101800151612a52565b6040518663ffffffff1660e01b8152600401611f17959493929190615632565b604080518083038186803b158015611f2e57600080fd5b505af4158015611f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f669190615348565b9092509050612022565b80156120225773b291730099d3ac9975abd4003ba3bd47401fd2fd63dee184ee8685848a60800151611fad8b8d61016001518e6101800151612a52565b6040518663ffffffff1660e01b8152600401611fcd959493929190615632565b604080518083038186803b158015611fe457600080fd5b505af4158015611ff8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201c9190615348565b90925090505b811580159061203057508015155b156120ce5760e0860151604051633d2945e960e11b815273b291730099d3ac9975abd4003ba3bd47401fd2fd91637a528bd2916120799189918990899089908990600401615595565b604080518083038186803b15801561209057600080fd5b505af41580156120a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c89190615348565b90925090505b61149a8660e00151858585856138a6565b604051630994094b60e21b8152600090736336788a85f54d8856782d58c1ca63c7d384453190632650252c90610eec90849086906004016158b4565b612123614a80565b6040516311c8197f60e01b8152736336788a85f54d8856782d58c1ca63c7d3844531906311c8197f90611049906000908690600401615ab8565b600f546001600160a01b031633146121875760405162461bcd60e51b815260040161084b9061578d565b60405163153cc2fd60e31b8152736336788a85f54d8856782d58c1ca63c7d38445319063a9e617e890610de2906000908590600401615ab8565b60006011546001146121e55760405162461bcd60e51b815260040161084b906156f7565b6000601181905560405163758e99b360e01b8152736336788a85f54d8856782d58c1ca63c7d38445319163758e99b3916115de91908690600d906004016158ff565b6011546001146122495760405162461bcd60e51b815260040161084b906156f7565b60006011819055604051631ae4f06f60e01b81528190736336788a85f54d8856782d58c1ca63c7d384453190631ae4f06f9061228b9084908790600401615ab8565b604080518083038186803b1580156122a257600080fd5b505af41580156122b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122da9190614fc7565b63ffffffff16915091506117fd8282856000612e52565b6001600160a01b03166000908152600d602052604090205490565b6004546001600160a01b031690565b33301461233a5760405162461bcd60e51b815260040161084b9061578d565b612345838383612b70565b505050565b60405163317e626f60e21b81526000908190736336788a85f54d8856782d58c1ca63c7d38445319063c5f989bc906123889084908790600401615ab8565b604080518083038186803b15801561239f57600080fd5b505af41580156123b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123d79190614fc7565b91509150915091565b600f546001600160a01b0316331461240a5760405162461bcd60e51b815260040161084b9061578d565b60405163b2456a0760e01b8152736336788a85f54d8856782d58c1ca63c7d38445319063b2456a0790612446906000908690869060040161588c565b60006040518083038186803b15801561245e57600080fd5b505af415801561149a573d6000803e3d6000fd5b60015490565b3330146124975760405162461bcd60e51b815260040161084b9061578d565b600e546001600160a01b0385811691161480156124b15750805b156125d4576040516306c5d9cf60e41b815260009073b28c804e3dacff80701bbbafd106dbfb416a516890636c5d9cf0906124f590600d908990889060040161588c565b60206040518083038186803b15801561250d57600080fd5b505af4158015612521573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125459190615330565b600e54604051632e1a7d4d60e01b81529192506001600160a01b031690632e1a7d4d906125769084906004016158ab565b600060405180830381600087803b15801561259057600080fd5b505af11580156125a4573d6000803e3d6000fd5b5050600080525050600a602052600080516020615d2b833981519152546125ce90859083906138c8565b50612668565b6040516306c5d9cf60e41b8152612668908590859073b28c804e3dacff80701bbbafd106dbfb416a516890636c5d9cf09061261890600d9086908a9060040161588c565b60206040518083038186803b15801561263057600080fd5b505af4158015612644573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b59190615330565b50505050565b60405163014ef18960e11b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063029de31290610eec90849086906004016158b4565b60025490565b6011546001146126d25760405162461bcd60e51b815260040161084b906156f7565b60006011556040517f892cd8f5b436bd5fb7dac1f11aafb73345d892ba3e9fe09cd94d95ba84928e73906127099033908490615541565b60405180910390a160005a3360009081526010602052604081205491925090819060ff168061276257506000805260106020527f6e0956cda88cad152e89927e53611735b61a5c762d1428573c6931b0a5efcb015460ff165b905060005b848110156128e0576002546001016000908152600b602052604090205460ff16156127f9576040516305d4bd1160e01b8152736336788a85f54d8856782d58c1ca63c7d3844531906305d4bd11906127c4906000906004016158ab565b60006040518083038186803b1580156127dc57600080fd5b505af41580156127f0573d6000803e3d6000fd5b505050506128d8565b600080612806600061395a565b9092509050600082600481111561281957fe5b14806128255750428110155b156128315750506128e0565b838061284157506104b081014210155b61285d5760405162461bcd60e51b815260040161084b9061578d565b600194508482600481111561286e57fe5b14156128815761287c61397e565b6128d5565b600282600481111561288f57fe5b141561289d5761287c613c36565b60038260048111156128ab57fe5b14156128b95761287c613eaf565b60048260048111156128c757fe5b14156128d5576128d5614128565b50505b600101612767565b50811561295c57736336788a85f54d8856782d58c1ca63c7d3844531639db74df1600061290e5a8790612ddb565b6040518363ffffffff1660e01b815260040161292b929190615ab8565b60006040518083038186803b15801561294357600080fd5b505af4158015612957573d6000803e3d6000fd5b505050505b505060016011555050565b60065490565b60019190910180546001600160a01b0319166001600160a01b03909216919091179055565b6000806000806000806000736336788a85f54d8856782d58c1ca63c7d3844531634e1eb86090918a6040518363ffffffff1660e01b81526004016129d7929190615ac6565b60606040518083038186803b1580156129ef57600080fd5b505af4158015612a03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a279190614d5f565b92509250925060008088612a3c578383612a3f565b82845b9598509650939450505050509250925092565b60606000846001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b158015612a8f57600080fd5b505afa158015612aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ac79190614d43565b6001600160a01b0316638c09166e85856040518363ffffffff1660e01b8152600401612af4929190615ac6565b60206040518083038186803b158015612b0c57600080fd5b505afa158015612b20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b449190615330565b905080604051602001612b5791906158ab565b6040516020818303038152906040529150509392505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b60208310612bec5780518252601f199092019160209182019101612bcd565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612c4e576040519150601f19603f3d011682016040523d82523d6000602084013e612c53565b606091505b5091509150818015612c81575080511580612c815750808060200190516020811015612c7e57600080fd5b50515b610e0e576040805162461bcd60e51b815260206004808301919091526024820152635448303560e01b604482015290519081900360640190fd5b600e54604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d90612ceb9084906004016158ab565b600060405180830381600087803b158015612d0557600080fd5b505af1158015612d19573d6000803e3d6000fd5b50506000808052600a602052600080516020615d2b833981519152546040519193506001600160a01b0386169250908490612d539061552a565b600060405180830381858888f193505050503d8060008114612d91576040519150601f19603f3d011682016040523d82523d6000602084013e612d96565b606091505b50509050806123455760405163032b310f60e51b815273b28c804e3dacff80701bbbafd106dbfb416a51689063656621e090611d2690600d908790879060040161588c565b6000612e0483836040518060400160405280600481526020016329a6989960e11b815250614293565b9392505050565b80820182811015612e4c576040805162461bcd60e51b81526020600480830191909152602482015263534d344560e01b604482015290519081900360640190fd5b92915050565b6000846004811115612e6057fe5b1415612e7e5760405162461bcd60e51b815260040161084b9061585f565b600042612e8f856301e13380612e0b565b1090506001856004811115612ea057fe5b14156130785760405163117d7ab160e01b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063117d7ab190612ee29084908890600401615ab8565b6101a06040518083038186803b158015612efb57600080fd5b505af4158015612f0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f339190615119565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091612f7591859190600401615ac6565b60606040518083038186803b158015612f8d57600080fd5b505af4158015612fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc59190614d5f565b9250925050600084612fdb578360e00151612fe8565b600f546001600160a01b03165b9050613004818486602001518588604001518960a0015161432b565b6130205760405162461bcd60e51b815260040161084b90615733565b851561306f57600061304585610120015186610100015161449190919063ffffffff16565b905061305182826144e6565b61306d5760405162461bcd60e51b815260040161084b906157c9565b505b505050506135dd565b600285600481111561308657fe5b141561324a57604051634ce4436960e11b8152600090736336788a85f54d8856782d58c1ca63c7d3844531906399c886d2906130c89084908890600401615ab8565b6101206040518083038186803b1580156130e157600080fd5b505af41580156130f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613119919061527b565b8051604051630270f5c360e51b8152919250600091736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613158918591600401615ac6565b60606040518083038186803b15801561317057600080fd5b505af4158015613184573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a89190614d5f565b505090506000836131bd578260a001516131ca565b600f546001600160a01b03165b90506131db82828560200151614567565b6131f75760405162461bcd60e51b815260040161084b90615733565b841561324257600061321a8460e001518560c0015161449190919063ffffffff16565b905061322682826144e6565b61306f5760405162461bcd60e51b815260040161084b906157c9565b5050506135dd565b600385600481111561325857fe5b14156134055760405163ac1ecdb360e01b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063ac1ecdb39061329a9084908890600401615ab8565b6101606040518083038186803b1580156132b357600080fd5b505af41580156132c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132eb9190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb8609161332d91859190600401615ac6565b60606040518083038186803b15801561334557600080fd5b505af4158015613359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337d9190614d5f565b9250925050600084613393578360a001516133a0565b600f546001600160a01b03165b90506133c684602001516133b457836133b6565b825b8286604001518760800151614676565b6133e25760405162461bcd60e51b815260040161084b90615733565b851561306f5760006130458560e001518660c0015161449190919063ffffffff16565b600485600481111561341357fe5b14156135dd576040516311c8197f60e01b8152600090736336788a85f54d8856782d58c1ca63c7d3844531906311c8197f906134559084908890600401615ab8565b6101606040518083038186803b15801561346e57600080fd5b505af4158015613482573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134a69190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb860916134e891859190600401615ac6565b60606040518083038186803b15801561350057600080fd5b505af4158015613514573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135389190614d5f565b925092505060008461354e578360a0015161355b565b600f546001600160a01b03165b905061356f84602001516133b457836133b6565b61358b5760405162461bcd60e51b815260040161084b90615733565b85156135d85760006135ae8560e001518660c0015161449190919063ffffffff16565b90506135ba82826144e6565b6135d65760405162461bcd60e51b815260040161084b906157c9565b505b505050505b610e0e600084614795565b8051604051630270f5c360e51b81526000918291829182918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb8609161362d91859190600401615ac6565b60606040518083038186803b15801561364557600080fd5b505af4158015613659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367d9190614d5f565b60208901516040516306c5d9cf60e41b8152939850919650945060009173b28c804e3dacff80701bbbafd106dbfb416a516891636c5d9cf0916136c891600d918a919060040161588c565b60206040518083038186803b1580156136e057600080fd5b505af41580156136f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137189190615330565b60408089015190516306c5d9cf60e41b815291925060009173b28c804e3dacff80701bbbafd106dbfb416a516891636c5d9cf09161375e91600d918a919060040161588c565b60206040518083038186803b15801561377657600080fd5b505af415801561378a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137ae9190615330565b9050866001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156137eb57600080fd5b505af11580156137ff573d6000803e3d6000fd5b5050505060e0880151604051633d2945e960e11b815273b291730099d3ac9975abd4003ba3bd47401fd2fd91637a528bd291613847918b918b908b9089908990600401615595565b604080518083038186803b15801561385e57600080fd5b505af4158015613872573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138969190615348565b9799969850949694959350505050565b81156138b7576138b7848684612b70565b8015610e0e57610e0e838683612b70565b6040516000906001600160a01b038516908390859084818181858888f193505050503d8060008114613916576040519150601f19603f3d011682016040523d82523d6000602084013e61391b565b606091505b5050905080612668576040805162461bcd60e51b815260206004808301919091526024820152632a2419a360e11b604482015290519081900360640190fd5b60008061396e8384600201546001016147c8565b90925063ffffffff169050915091565b60005a60405163a81df10f60e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d38445319063a81df10f906139be9084906004016158ab565b6101a06040518083038186803b1580156139d757600080fd5b505af41580156139eb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a0f9190615119565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613a5191859190600401615ac6565b60606040518083038186803b158015613a6957600080fd5b505af4158015613a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613aa19190614d5f565b6001600160a01b038082166000908152600a602052604080822054928516825281205493965091945090925082913091613af491613ae891906117af9062012c6c90612e0b565b61012088015190612ddb565b604051634ed4967d60e11b90613b0e908990602401615ada565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613b4c919061550e565b60006040518083038160008787f1925050503d8060008114613b8a576040519150601f19603f3d011682016040523d82523d6000602084013e613b8f565b606091505b509092509050600182613bbd57613bba8660e00151868860200151878a604001518b60a0015161432b565b90505b613bc6816147fe565b600080613be38861012001518961010001518b8b60e0015161481f565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613c239392919061569d565b60405180910390a3505050505050505050565b60005a6040516313ed2f6160e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d3844531906313ed2f6190613c769084906004016158ab565b6101206040518083038186803b158015613c8f57600080fd5b505af4158015613ca3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cc7919061527b565b905060008030613cea613cdf62012c6c61d6d8612e0b565b60e086015190612ddb565b604051631a42443160e21b90613d04908790602401615ba0565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613d42919061550e565b60006040518083038160008787f1925050503d8060008114613d80576040519150601f19603f3d011682016040523d82523d6000602084013e613d85565b606091505b509092509050600182613e3a578351604051630270f5c360e51b8152600091736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613dcf91859190600401615ac6565b60606040518083038186803b158015613de757600080fd5b505af4158015613dfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e1f9190614d5f565b50509050613e36818660a001518760200151614567565b9150505b613e43816147fe565b600080613e5e8660e001518760c00151898960a0015161481f565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613e9e9392919061569d565b60405180910390a350505050505050565b60005a604051632e9d30e160e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d384453190632e9d30e190613eef9084906004016158ab565b6101606040518083038186803b158015613f0857600080fd5b505af4158015613f1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f409190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613f8291859190600401615ac6565b60606040518083038186803b158015613f9a57600080fd5b505af4158015613fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fd29190614d5f565b9250925050600080306001600160a01b03166140316140266000600a01600089602001516140005788614002565b875b6001600160a01b0316815260208101919091526040016000205462012c6c90612e0b565b60e088015190612ddb565b604051630b65604d60e01b9061404b90899060240161587d565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614089919061550e565b60006040518083038160008787f1925050503d80600081146140c7576040519150601f19603f3d011682016040523d82523d6000602084013e6140cc565b606091505b5090925090506001826141045761410186602001516140eb57856140ed565b845b8760a0015188604001518960800151614676565b90505b61410d816147fe565b600080613be38860e001518960c001518b8b60a0015161481f565b60005a60405163a1ba139560e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d38445319063a1ba1395906141689084906004016158ab565b6101606040518083038186803b15801561418157600080fd5b505af4158015614195573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141b99190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb860916141fb91859190600401615ac6565b60606040518083038186803b15801561421357600080fd5b505af4158015614227573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061424b9190614d5f565b9250925050600080306001600160a01b03166142796140266000600a01600089602001516140005788614002565b604051633c763c1760e01b9061404b90899060240161587d565b81830381848211156143235760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156142e85781810151838201526020016142d0565b50505050905090810190601f1680156143155780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509392505050565b6001600160a01b038381166000908152600a6020526040808220549288168252812054909182918291309161435f91612e0b565b604051633ed76f1760e01b90614383908d908d908d908d908d908d906024016155cf565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516143c1919061550e565b60006040518083038160008787f1925050503d80600081146143ff576040519150601f19603f3d011682016040523d82523d6000602084013e614404565b606091505b50915091508161448557876001600160a01b0316896001600160a01b0316600080516020615d0b8339815191528984604051614441929190615c17565b60405180910390a3856001600160a01b0316896001600160a01b0316600080516020615d0b833981519152878460405161447c929190615c17565b60405180910390a35b50979650505050505050565b60008115806144ac575050808202828282816144a957fe5b04145b612e4c576040805162461bcd60e51b81526020600480830191909152602482015263534d324160e01b604482015290519081900360640190fd5b6000816144f557506001612e4c565b60008052600a602052600080516020615d2b8339815191525461451b90849084906148af565b9050801515836001600160a01b03167fdbef2fc26e7694e7a1c5a4801b1ad144136d149cf76f310a780689b4087f0ffe8460405161455991906158ab565b60405180910390a392915050565b60008161457657506001612e04565b600080306001600160a01b031661d6d863c9cd976060e01b88888860006040516024016145a69493929190615609565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516145e4919061550e565b60006040518083038160008787f1925050503d8060008114614622576040519150601f19603f3d011682016040523d82523d6000602084013e614627565b606091505b50915091508161466d57856001600160a01b0316856001600160a01b0316600080516020615d0b8339815191528684604051614664929190615c17565b60405180910390a35b50949350505050565b6000826146855750600161478d565b6001600160a01b0385166000908152600a60205260408082205490518291309163e5b1be6560e01b906146c2908b908b908b908b90602401615609565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614700919061550e565b60006040518083038160008787f1925050503d806000811461473e576040519150601f19603f3d011682016040523d82523d6000602084013e614743565b606091505b50915091508161478957866001600160a01b0316866001600160a01b0316600080516020615d0b8339815191528784604051614780929190615c17565b60405180910390a35b5090505b949350505050565b6000908152600391820160205260408120818155600181018290556002810180546001600160e81b031916905590910155565b60008181526003830160205260408120805463ffffffff610100820416919060ff166147f38161490d565b935050509250929050565b806148125761480d600061497d565b61481c565b61481c60006149d0565b50565b6000808061482d8787614491565b90506148406155946117af5a8890612ddb565b92506000614865826148606000600601548761449190919063ffffffff16565b614a07565b90506148718282612ddb565b925061487d33826144e6565b6148995760405162461bcd60e51b815260040161084b906157c9565b6148a385846144e6565b50505094509492505050565b6040516000906001600160a01b038516908390859084818181858888f193505050503d80600081146148fd576040519150601f19603f3d011682016040523d82523d6000602084013e614902565b606091505b509095945050505050565b6000600182141561492057506001610eab565b600282141561493157506002610eab565b600382141561494257506004610eab565b600482141561495357506004610eab565b600582141561496457506003610eab565b600682141561497557506003610eab565b506000919050565b600281015460009081526003820160205260409020805465010000000000900460ff16156149ac5760036149af565b60025b815460ff91909116650100000000000265ff00000000001990911617905550565b60028082015460009081526003928301602052604081208181556001810182905591820180546001600160e81b0319169055910155565b6000818310614a165781612e04565b5090919050565b604051806101200160405280600063ffffffff16815260200160008152602001600081526020016000815260200160001515815260200160006001600160a01b031681526020016000815260200160008152602001600063ffffffff1681525090565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b604051806101a00160405280600063ffffffff1681526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160006001600160a01b031681526020016000815260200160008152602001600063ffffffff16815260200160008152602001600063ffffffff1681525090565b8035610eab81615cc8565b8051610eab81615cc8565b8035610eab81615cdd565b8051610eab81615cdd565b6000610160808385031215614ba2578182fd5b614bab81615c78565b915050614bb782614d11565b8152614bc560208301614b79565b60208201526040820135604082015260608201356060820152614bea60808301614b79565b6080820152614bfb60a08301614b63565b60a082015260c082013560c082015260e082013560e0820152610100614c22818401614d11565b908201526101208281013590820152610140614c3f818401614d11565b9082015292915050565b6000610160808385031215614c5c578182fd5b614c6581615c78565b915050614c7182614d1c565b8152614c7f60208301614b84565b60208201526040820151604082015260608201516060820152614ca460808301614b84565b6080820152614cb560a08301614b6e565b60a082015260c082015160c082015260e082015160e0820152610100614cdc818401614d1c565b908201526101208281015190820152610140614c3f818401614d1c565b60006101008284031215614d0b578081fd5b50919050565b8035610eab81615cf8565b8051610eab81615cf8565b600060208284031215614d38578081fd5b8135612e0481615cc8565b600060208284031215614d54578081fd5b8151612e0481615cc8565b600080600060608486031215614d73578182fd5b8351614d7e81615cc8565b6020850151909350614d8f81615cc8565b6040850151909250614da081615cc8565b809150509250925092565b600080600060608486031215614dbf578081fd5b8335614dca81615cc8565b92506020840135614dda81615cc8565b929592945050506040919091013590565b60008060008060008060c08789031215614e03578384fd5b8635614e0e81615cc8565b95506020870135614e1e81615cc8565b9450604087013593506060870135614e3581615cc8565b92506080870135915060a0870135614e4c81615cdd565b809150509295509295509295565b60008060008060808587031215614e6f578182fd5b8435614e7a81615cc8565b93506020850135614e8a81615cc8565b9250604085013591506060850135614ea181615cdd565b939692955090935050565b60008060408385031215614ebe578182fd5b8235614ec981615cc8565b91506020830135614ed981615cdd565b809150509250929050565b600080600060608486031215614ef8578081fd5b8335614f0381615cc8565b92506020840135614f1381615ceb565b91506040840135614da081615cdd565b60008060408385031215614f35578182fd5b8235614f4081615cc8565b946020939093013593505050565b600060208284031215614f5f578081fd5b8151612e0481615cdd565b60008060008060808587031215614f7f578182fd5b8451614f8a81615cdd565b60208601516040870151606090970151919890975090945092505050565b600060208284031215614fb9578081fd5b815160068110612e04578182fd5b60008060408385031215614fd9578182fd5b8251614fe481615ceb565b6020840151909250614ed981615cf8565b60006101608284031215615007578081fd5b612e048383614b8f565b60006101608284031215615023578081fd5b612e048383614c49565b6000610100828403121561503f578081fd5b612e048383614cf9565b60006101a080838503121561505c578182fd5b61506581615c78565b905061507083614d11565b8152602083013560208201526040830135604082015260608301356060820152608083013560808201526150a660a08401614b79565b60a08201526150b760c08401614b79565b60c08201526150c860e08401614b63565b60e0820152610100838101359082015261012080840135908201526101406150f1818501614d11565b90820152610160838101359082015261018061510e818501614d11565b908201529392505050565b60006101a080838503121561512c578182fd5b61513581615c78565b905061514083614d1c565b81526020830151602082015260408301516040820152606083015160608201526080830151608082015261517660a08401614b84565b60a082015261518760c08401614b84565b60c082015261519860e08401614b6e565b60e0820152610100838101519082015261012080840151908201526101406151c1818501614d1c565b90820152610160838101519082015261018061510e818501614d1c565b60006101608284031215614d0b578081fd5b6000610120808385031215615203578182fd5b61520c81615c78565b905061521783614d11565b815260208301356020820152604083013560408201526060830135606082015261524360808401614b79565b608082015261525460a08401614b63565b60a082015260c083013560c082015260e083013560e082015261010061510e818501614d11565b600061012080838503121561528e578182fd5b61529781615c78565b90506152a283614d1c565b81526020830151602082015260408301516040820152606083015160608201526152ce60808401614b84565b60808201526152df60a08401614b6e565b60a082015260c083015160c082015260e083015160e082015261010061510e818501614d1c565b60006101208284031215614d0b578081fd5b600060208284031215615329578081fd5b5035919050565b600060208284031215615341578081fd5b5051919050565b6000806040838503121561535a578182fd5b505080516020909101519092909150565b60006020828403121561537c578081fd5b8135612e0481615cf8565b6001600160a01b03169052565b15159052565b600081518084526153b2816020860160208601615c9c565b601f01601f19169290920160200192915050565b600581106153d057fe5b9052565b6153df828251615504565b60208101516153f16020840182615394565b50604081015160408301526060810151606083015260808101516154186080840182615394565b5060a081015161542b60a0840182615387565b5060c081015160c083015260e081015160e08301526101008082015161545382850182615504565b505061012081810151908301526101408082015161266882850182615504565b803561547e81615cc8565b6001600160a01b03908116835260208201359061549a82615cc8565b166020830152604081810135908301526060808201359083015260808101356154c281615cdd565b1515608083015260a08101356154d781615cc8565b6154e460a0840182615387565b5060c081013560c08301526154fb60e08201614d11565b61234560e08401825b63ffffffff169052565b60008251615520818460208701615c9c565b9190910192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039687168152948616602086015292851660408501529084166060840152909216608082015260a081019190915260c00190565b6001600160a01b0396871681529486166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b6001600160a01b0396871681529486166020860152604085019390935293166060830152608082019290925290151560a082015260c00190565b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061566c9083018461539a565b979650505050505050565b6001600160a01b039290921682521515602082015260400190565b901515815260200190565b6000606082526156b0606083018661539a565b60208301949094525060400152919050565b60208101600683106156d057fe5b91905290565b604081016156e482856153c6565b63ffffffff831660208301529392505050565b6020808252600490820152632a22181b60e11b604082015260600190565b6020808252600490820152635444314360e01b604082015260600190565b60208082526004908201526315110c4d60e21b604082015260600190565b6020808252600490820152635444303360e01b604082015260600190565b6020808252600490820152635444333760e01b604082015260600190565b6020808252600490820152630544430360e41b604082015260600190565b6020808252600490820152635444303160e01b604082015260600190565b6020808252600490820152630544434360e41b604082015260600190565b60208082526004908201526315110c0d60e21b604082015260600190565b6020808252600490820152632a221a9960e11b604082015260600190565b6020808252600490820152632a22181960e11b604082015260600190565b6020808252600490820152630a88860760e31b604082015260600190565b6020808252600490820152635444343160e01b604082015260600190565b6101608101612e4c82846153d4565b9283526001600160a01b03919091166020830152604082015260600190565b90815260200190565b9182526001600160a01b0316602082015260400190565b8481526001600160a01b0384166020820152608081016158ee60408301856153c6565b821515606083015295945050505050565b83815261014081016159146020830185615473565b82610120830152949350505050565b8381526101a081016159406020830161593b86614b63565b615387565b61594c60208501614b63565b6159596040840182615387565b506040840135606083015260608401356080830152608084013560a083015260a084013560c083015261598e60c08501614b79565b61599b60e0840182615394565b506159a860e08501614b79565b6101006159b781850183615394565b6159c2818701614b63565b9150506101206159d481850183615387565b61014091508086013582850152506159ed818601614d11565b90506159fd610160840182615504565b5082610180830152949350505050565b8281526101408101615a256020830161593b85614b63565b615a3160208401614b63565b615a3e6040840182615387565b506040830135606083015260608301356080830152608083013560a0830152615a6960a08401614b79565b615a7660c0840182615394565b50615a8360c08401614b63565b615a9060e0840182615387565b5061010060e084013581840152615aa8818501614d11565b9050614323610120840182615504565b918252602082015260400190565b91825263ffffffff16602082015260400190565b60006101a082019050615aee828451615504565b6020830151602083015260408301516040830152606083015160608301526080830151608083015260a0830151615b2860a0840182615394565b5060c0830151615b3b60c0840182615394565b5060e0830151615b4e60e0840182615387565b506101008381015190830152610120808401519083015261014080840151615b7882850182615504565b5050610160838101519083015261018080840151615b9882850182615504565b505092915050565b60006101208201905063ffffffff835116825260208301516020830152604083015160408301526060830151606083015260808301511515608083015260a0830151615bef60a0840182615387565b5060c083015160c083015260e083015160e083015261010080840151615b9882850182615504565b60008382526040602083015261478d604083018461539a565b600085825284602083015260018060a01b038416604083015260806060830152615c5d608083018461539a565b9695505050505050565b63ffffffff91909116815260200190565b60405181810167ffffffffffffffff81118282101715615c9457fe5b604052919050565b60005b83811015615cb7578181015183820152602001615c9f565b838111156126685750506000910152565b6001600160a01b038116811461481c57600080fd5b801515811461481c57600080fd5b6005811061481c57600080fd5b63ffffffff8116811461481c57600080fdfe786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b21159213da86008ba1c6922daee3e07db95305ef49ebced9f5467a0b8613fcc6b343e3a26469706673582212204869fe8a86a81d32e462924c6375438fb998a95decb6fe160a341c323c1eee6f64736f6c63430007060033000000000000000000000000c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c6000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000003a1d749fa4a9e650fce844ff1c58c5faf7e2a9d1

Deployed Bytecode

0x6080604052600436106102815760003560e01c806377632ec21161014f578063be581304116100c1578063e30a49931161007a578063e30a49931461078d578063e5b1be65146107a2578063e5e7988e146107c2578063e6a0cc94146107e2578063fe0d94c1146107f7578063fe173b971461081757610288565b8063be581304146106ca578063bf6b874e146106ea578063c45a01551461070a578063c9cd97601461071f578063d09ef2411461073f578063d22e92421461076d57610288565b80639d08ebb5116101135780639d08ebb5146106245780639da92cfa14610637578063af482b5814610657578063b1af1bda14610677578063b32ac93614610697578063ba4d5312146106b757610288565b806377632ec21461058f5780637f6a1caf146105af5780638da5cb5b146105cf57806394531713146105e45780639718f6271461060457610288565b80633fc8cef3116101f3578063576b332b116101ac578063576b332b146104fb57806357a62a4f1461050e5780635e45da2314610523578063690910c4146105385780636a42b8f8146105585780636de3c67c1461057a57610288565b80633fc8cef31461041f57806345fa8aae146104415780634c0160161461046e5780635051349a1461048e578063514fcac7146104ae57806354df6d74146104ce57610288565b806320a68fab1161024557806320a68fab14610345578063342aa8b514610372578063390ce0d3146103925780633bbac579146103bf5780633c763c17146103df5780633ed76f17146103ff57610288565b80630b65604d1461028d57806310348665146102af57806313af4035146102cf5780631776834a146102ef57806317818a5c1461030f57610288565b3661028857005b600080fd5b34801561029957600080fd5b506102ad6102a8366004614ff5565b61082c565b005b3480156102bb57600080fd5b506102ad6102ca36600461536b565b610c10565b3480156102db57600080fd5b506102ad6102ea366004614d27565b610cb5565b3480156102fb57600080fd5b506102ad61030a366004615318565b610d7e565b34801561031b57600080fd5b5061032f61032a366004615318565b610e15565b60405161033c9190615ba0565b60405180910390f35b34801561035157600080fd5b50610365610360366004614d27565b610eb0565b60405161033c9190615692565b34801561037e57600080fd5b506102ad61038d366004614eac565b610f3c565b34801561039e57600080fd5b506103b26103ad366004615318565b611007565b60405161033c919061587d565b3480156103cb57600080fd5b506103656103da366004614d27565b61109a565b3480156103eb57600080fd5b506102ad6103fa366004614ff5565b6110af565b34801561040b57600080fd5b506102ad61041a366004614deb565b611482565b34801561042b57600080fd5b506104346114a2565b60405161033c919061552d565b34801561044d57600080fd5b5061046161045c366004615318565b6114b1565b60405161033c91906156c2565b34801561047a57600080fd5b50610365610489366004614d27565b61153d565b6104a161049c36600461502d565b611579565b60405161033c91906158ab565b3480156104ba57600080fd5b506102ad6104c9366004615318565b61161d565b3480156104da57600080fd5b506104ee6104e9366004615318565b611807565b60405161033c9190615ada565b6104a1610509366004615306565b61189a565b34801561051a57600080fd5b506104a16118fd565b34801561052f57600080fd5b506104a1611903565b34801561054457600080fd5b506102ad6105533660046151f0565b611909565b34801561056457600080fd5b5061056d611c97565b60405161033c9190615c67565b34801561058657600080fd5b506104a1611ca3565b34801561059b57600080fd5b506103656105aa366004615318565b611ca9565b3480156105bb57600080fd5b506102ad6105ca366004614ee4565b611cbe565b3480156105db57600080fd5b50610434611d52565b3480156105f057600080fd5b506102ad6105ff366004615318565b611d61565b34801561061057600080fd5b506104a161061f366004614d27565b611dc5565b6104a16106323660046151de565b611de0565b34801561064357600080fd5b506102ad610652366004615049565b611e46565b34801561066357600080fd5b50610365610672366004614d27565b6120df565b34801561068357600080fd5b506103b2610692366004615318565b61211b565b3480156106a357600080fd5b506102ad6106b2366004615318565b61215d565b6104a16106c536600461502d565b6121c1565b3480156106d657600080fd5b506102ad6106e5366004615318565b612227565b3480156106f657600080fd5b506104a1610705366004614d27565b6122f1565b34801561071657600080fd5b5061043461230c565b34801561072b57600080fd5b506102ad61073a366004614dab565b61231b565b34801561074b57600080fd5b5061075f61075a366004615318565b61234a565b60405161033c9291906156d6565b34801561077957600080fd5b506102ad610788366004614f23565b6123e0565b34801561079957600080fd5b506104a1612472565b3480156107ae57600080fd5b506102ad6107bd366004614e5a565b612478565b3480156107ce57600080fd5b506103656107dd366004614d27565b61266e565b3480156107ee57600080fd5b506104a16126aa565b34801561080357600080fd5b506102ad610812366004615318565b6126b0565b34801561082357600080fd5b506104a1612967565b3330146108545760405162461bcd60e51b815260040161084b9061578d565b60405180910390fd5b426202a30082610100015163ffffffff160110156108845760405162461bcd60e51b815260040161084b906157e7565b600080600061089b84600001518560200151612992565b9250925092506000600d73b28c804e3dacff80701bbbafd106dbfb416a5168636c5d9cf090918588604001516040518463ffffffff1660e01b81526004016108e59392919061588c565b60206040518083038186803b1580156108fd57600080fd5b505af4158015610911573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109359190615330565b90506000849050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561097757600080fd5b505af115801561098b573d6000803e3d6000fd5b5050505060006109a686886101200151896101400151612a52565b905060008760200151610a3657604051632b9b015d60e01b81526001600160a01b03841690632b9b015d906109e19087908690600401615c17565b60206040518083038186803b1580156109f957600080fd5b505afa158015610a0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a319190615330565b610ab4565b6040516302b97d6d60e21b81526001600160a01b03841690630ae5f5b490610a649087908690600401615c17565b60206040518083038186803b158015610a7c57600080fd5b505afa158015610a90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab49190615330565b90508760600151811015610ada5760405162461bcd60e51b815260040161084b9061576f565b6000808960200151610aee57600083610af2565b8260005b91509150610b01888a88612b70565b600e546001600160a01b038881169116148015610b1f575089608001515b15610b9b5760405163022c0d9f60e01b81526001600160a01b0386169063022c0d9f90610b56908590859030908a90600401615c30565b600060405180830381600087803b158015610b7057600080fd5b505af1158015610b84573d6000803e3d6000fd5b50505050610b968a60a0015184612cbb565b610c04565b60a08a015160405163022c0d9f60e01b81526001600160a01b0387169163022c0d9f91610bd19186918691908a90600401615c30565b600060405180830381600087803b158015610beb57600080fd5b505af1158015610bff573d6000803e3d6000fd5b505050505b50505050505050505050565b600f546001600160a01b03163314610c3a5760405162461bcd60e51b815260040161084b9061578d565b60005463ffffffff82811691161415610c655760405162461bcd60e51b815260040161084b906157ab565b6000805463ffffffff191663ffffffff83161790556040517f63e09f16584208fba1fc7ff64c62b00f07bec177c0d97ca6689891b1e77a35c790610caa908390615c67565b60405180910390a150565b600f546001600160a01b03163314610cdf5760405162461bcd60e51b815260040161084b9061578d565b600f546001600160a01b0382811691161415610d0d5760405162461bcd60e51b815260040161084b906157ab565b6001600160a01b038116610d335760405162461bcd60e51b815260040161084b90615823565b600f80546001600160a01b0319166001600160a01b0383161790556040517f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe290610caa90839061552d565b600f546001600160a01b03163314610da85760405162461bcd60e51b815260040161084b9061578d565b604051636702eca360e01b8152736336788a85f54d8856782d58c1ca63c7d384453190636702eca390610de2906000908590600401615ab8565b60006040518083038186803b158015610dfa57600080fd5b505af4158015610e0e573d6000803e3d6000fd5b5050505050565b610e1d614a1d565b604051634ce4436960e11b8152736336788a85f54d8856782d58c1ca63c7d3844531906399c886d290610e57906000908690600401615ab8565b6101206040518083038186803b158015610e7057600080fd5b505af4158015610e84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea8919061527b565b90505b919050565b604051631ae4448160e31b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063d722240890610eec90849086906004016158b4565b60206040518083038186803b158015610f0457600080fd5b505af4158015610f18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190614f4e565b600f546001600160a01b03163314610f665760405162461bcd60e51b815260040161084b9061578d565b6001600160a01b03821660009081526010602052604090205460ff1615158115151415610fa55760405162461bcd60e51b815260040161084b906157ab565b6001600160a01b03821660009081526010602052604090819020805460ff1916831515179055517f70af441dbb427737e6a5ef2cf5b664321011765ce1d19ce4a69cd024e69d4f2f90610ffb9084908490615677565b60405180910390a15050565b61100f614a80565b60405163ac1ecdb360e01b8152736336788a85f54d8856782d58c1ca63c7d38445319063ac1ecdb390611049906000908690600401615ab8565b6101606040518083038186803b15801561106257600080fd5b505af4158015611076573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190615011565b60106020526000908152604090205460ff1681565b3330146110ce5760405162461bcd60e51b815260040161084b9061578d565b426202a30082610100015163ffffffff160110156110fe5760405162461bcd60e51b815260040161084b906157e7565b600080600061111584600001518560200151612992565b9250925092506000600d73b28c804e3dacff80701bbbafd106dbfb416a5168636c5d9cf090918588604001516040518463ffffffff1660e01b815260040161115f9392919061588c565b60206040518083038186803b15801561117757600080fd5b505af415801561118b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111af9190615330565b90506000849050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156111f157600080fd5b505af1158015611205573d6000803e3d6000fd5b50505050600061122086886101200151896101400151612a52565b9050600087602001516112b457606088015160405163c7481b8f60e01b81526001600160a01b0385169163c7481b8f9161125f91908690600401615c17565b60206040518083038186803b15801561127757600080fd5b505afa15801561128b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112af9190615330565b611336565b606088015160405163d6945d8960e01b81526001600160a01b0385169163d6945d89916112e691908690600401615c17565b60206040518083038186803b1580156112fe57600080fd5b505afa158015611312573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113369190615330565b9050808410156113585760405162461bcd60e51b815260040161084b90615841565b808411156113ba57600e546001600160a01b03878116911614801561137e575087608001515b156113a05760a088015161139b906113968684612ddb565b612cbb565b6113ba565b60a08801516113ba9087906113b58785612ddb565b612b70565b60008089602001516113d25760008a606001516113da565b896060015160005b915091506113e9888a85612b70565b600e546001600160a01b038881169116148015611407575089608001515b15610b9b5760405163022c0d9f60e01b81526001600160a01b0386169063022c0d9f9061143e908590859030908a90600401615c30565b600060405180830381600087803b15801561145857600080fd5b505af115801561146c573d6000803e3d6000fd5b50505050610b968a60a001518b60600151612cbb565b61148e85878684612478565b61149a83878484612478565b505050505050565b600e546001600160a01b031690565b604051634dc1ffe760e11b8152600090736336788a85f54d8856782d58c1ca63c7d384453190639b83ffce906114ed9084908690600401615ab8565b60206040518083038186803b15801561150557600080fd5b505af4158015611519573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190614fa8565b604051634d95367160e11b8152600090736336788a85f54d8856782d58c1ca63c7d384453190639b2a6ce290610eec90849086906004016158b4565b600060115460011461159d5760405162461bcd60e51b815260040161084b906156f7565b6000601181905560405162c44ff160e31b8152736336788a85f54d8856782d58c1ca63c7d3844531916306227f88916115de91908690600d906004016158ff565b60006040518083038186803b1580156115f657600080fd5b505af415801561160a573d6000803e3d6000fd5b5050600154925050506001601155919050565b60115460011461163f5760405162461bcd60e51b815260040161084b906156f7565b60006011556002604051634dc1ffe760e11b8152736336788a85f54d8856782d58c1ca63c7d384453190639b83ffce90611680906000908690600401615ab8565b60206040518083038186803b15801561169857600080fd5b505af41580156116ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d09190614fa8565b60058111156116db57fe5b146116f85760405162461bcd60e51b815260040161084b90615805565b60405163317e626f60e21b81526000908190736336788a85f54d8856782d58c1ca63c7d38445319063c5f989bc906117369084908790600401615ab8565b604080518083038186803b15801561174d57600080fd5b505af4158015611761573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117859190614fc7565b60005491935063ffffffff908116925042916117b59162015180916117af918691811690612ddb16565b90612e0b565b106117d25760405162461bcd60e51b815260040161084b90615715565b6000838152600b60205260409020805460ff191660019081179091556117fd90839083908690612e52565b5050600160115550565b61180f614adc565b60405163117d7ab160e01b8152736336788a85f54d8856782d58c1ca63c7d38445319063117d7ab190611849906000908690600401615ab8565b6101a06040518083038186803b15801561186257600080fd5b505af4158015611876573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190615119565b60006011546001146118be5760405162461bcd60e51b815260040161084b906156f7565b60006011819055604051636587992160e01b8152736336788a85f54d8856782d58c1ca63c7d3844531916365879921916115de91908690600401615a0d565b60085490565b60055490565b3330146119285760405162461bcd60e51b815260040161084b9061578d565b426202a30082610100015163ffffffff160110156119585760405162461bcd60e51b815260040161084b906157e7565b8051604051630270f5c360e51b815260009182918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb8609161199991859190600401615ac6565b60606040518083038186803b1580156119b157600080fd5b505af41580156119c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e99190614d5f565b925092509250826001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a2a57600080fd5b505af1158015611a3e573d6000803e3d6000fd5b50505050611a5183848660200151612b70565b6080840151600090819081908015611a8d5750600e546001600160a01b0386811691161480611a8d5750600e546001600160a01b038581169116145b15611bd357600e5460a08801516000808052600a602052600080516020615d2b8339815191525460405163cf58beed60e01b81529193736195015b38773f468dd43620dd5a64e9bb63c2e39363cf58beed93611aff938c938c938f936001600160a01b0390921692909160040161555a565b60806040518083038186803b158015611b1757600080fd5b505af4158015611b2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b4f9190614f6a565b91965094509250905080611bcd5760a088015160405163032b310f60e51b815273b28c804e3dacff80701bbbafd106dbfb416a51689163656621e091611b9c91600d91899060040161588c565b60006040518083038186803b158015611bb457600080fd5b505af4158015611bc8573d6000803e3d6000fd5b505050505b50611c5a565b60a087015160405163226bf2d160e21b81526001600160a01b038816916389afcb4491611c03919060040161552d565b6040805180830381600087803b158015611c1c57600080fd5b505af1158015611c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c549190615348565b90925090505b86604001518210158015611c72575086606001518110155b611c8e5760405162461bcd60e51b815260040161084b90615751565b50505050505050565b60005463ffffffff1690565b60075490565b6000908152600b602052604090205460ff1690565b600f546001600160a01b03163314611ce85760405162461bcd60e51b815260040161084b9061578d565b60405163146bce4f60e31b8152736336788a85f54d8856782d58c1ca63c7d38445319063a35e727890611d26906000908790879087906004016158cb565b60006040518083038186803b158015611d3e57600080fd5b505af4158015611c8e573d6000803e3d6000fd5b600f546001600160a01b031681565b600f546001600160a01b03163314611d8b5760405162461bcd60e51b815260040161084b9061578d565b604051630fd1437d60e11b8152736336788a85f54d8856782d58c1ca63c7d384453190631fa286fa90610de2906000908590600401615ab8565b6001600160a01b03166000908152600a602052604090205490565b6000601154600114611e045760405162461bcd60e51b815260040161084b906156f7565b60006011819055604051638f0e6bef60e01b8152736336788a85f54d8856782d58c1ca63c7d384453191638f0e6bef916115de91908690600d90600401615923565b333014611e655760405162461bcd60e51b815260040161084b9061578d565b426202a30082610140015163ffffffff16011015611e955760405162461bcd60e51b815260040161084b906157e7565b6000806000806000611ea6866135e8565b945094509450945094508560c0015115612022578115611f705773b291730099d3ac9975abd4003ba3bd47401fd2fd6388aae0878686858a60600151611ef78b8d61016001518e6101800151612a52565b6040518663ffffffff1660e01b8152600401611f17959493929190615632565b604080518083038186803b158015611f2e57600080fd5b505af4158015611f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f669190615348565b9092509050612022565b80156120225773b291730099d3ac9975abd4003ba3bd47401fd2fd63dee184ee8685848a60800151611fad8b8d61016001518e6101800151612a52565b6040518663ffffffff1660e01b8152600401611fcd959493929190615632565b604080518083038186803b158015611fe457600080fd5b505af4158015611ff8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201c9190615348565b90925090505b811580159061203057508015155b156120ce5760e0860151604051633d2945e960e11b815273b291730099d3ac9975abd4003ba3bd47401fd2fd91637a528bd2916120799189918990899089908990600401615595565b604080518083038186803b15801561209057600080fd5b505af41580156120a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c89190615348565b90925090505b61149a8660e00151858585856138a6565b604051630994094b60e21b8152600090736336788a85f54d8856782d58c1ca63c7d384453190632650252c90610eec90849086906004016158b4565b612123614a80565b6040516311c8197f60e01b8152736336788a85f54d8856782d58c1ca63c7d3844531906311c8197f90611049906000908690600401615ab8565b600f546001600160a01b031633146121875760405162461bcd60e51b815260040161084b9061578d565b60405163153cc2fd60e31b8152736336788a85f54d8856782d58c1ca63c7d38445319063a9e617e890610de2906000908590600401615ab8565b60006011546001146121e55760405162461bcd60e51b815260040161084b906156f7565b6000601181905560405163758e99b360e01b8152736336788a85f54d8856782d58c1ca63c7d38445319163758e99b3916115de91908690600d906004016158ff565b6011546001146122495760405162461bcd60e51b815260040161084b906156f7565b60006011819055604051631ae4f06f60e01b81528190736336788a85f54d8856782d58c1ca63c7d384453190631ae4f06f9061228b9084908790600401615ab8565b604080518083038186803b1580156122a257600080fd5b505af41580156122b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122da9190614fc7565b63ffffffff16915091506117fd8282856000612e52565b6001600160a01b03166000908152600d602052604090205490565b6004546001600160a01b031690565b33301461233a5760405162461bcd60e51b815260040161084b9061578d565b612345838383612b70565b505050565b60405163317e626f60e21b81526000908190736336788a85f54d8856782d58c1ca63c7d38445319063c5f989bc906123889084908790600401615ab8565b604080518083038186803b15801561239f57600080fd5b505af41580156123b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123d79190614fc7565b91509150915091565b600f546001600160a01b0316331461240a5760405162461bcd60e51b815260040161084b9061578d565b60405163b2456a0760e01b8152736336788a85f54d8856782d58c1ca63c7d38445319063b2456a0790612446906000908690869060040161588c565b60006040518083038186803b15801561245e57600080fd5b505af415801561149a573d6000803e3d6000fd5b60015490565b3330146124975760405162461bcd60e51b815260040161084b9061578d565b600e546001600160a01b0385811691161480156124b15750805b156125d4576040516306c5d9cf60e41b815260009073b28c804e3dacff80701bbbafd106dbfb416a516890636c5d9cf0906124f590600d908990889060040161588c565b60206040518083038186803b15801561250d57600080fd5b505af4158015612521573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125459190615330565b600e54604051632e1a7d4d60e01b81529192506001600160a01b031690632e1a7d4d906125769084906004016158ab565b600060405180830381600087803b15801561259057600080fd5b505af11580156125a4573d6000803e3d6000fd5b5050600080525050600a602052600080516020615d2b833981519152546125ce90859083906138c8565b50612668565b6040516306c5d9cf60e41b8152612668908590859073b28c804e3dacff80701bbbafd106dbfb416a516890636c5d9cf09061261890600d9086908a9060040161588c565b60206040518083038186803b15801561263057600080fd5b505af4158015612644573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b59190615330565b50505050565b60405163014ef18960e11b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063029de31290610eec90849086906004016158b4565b60025490565b6011546001146126d25760405162461bcd60e51b815260040161084b906156f7565b60006011556040517f892cd8f5b436bd5fb7dac1f11aafb73345d892ba3e9fe09cd94d95ba84928e73906127099033908490615541565b60405180910390a160005a3360009081526010602052604081205491925090819060ff168061276257506000805260106020527f6e0956cda88cad152e89927e53611735b61a5c762d1428573c6931b0a5efcb015460ff165b905060005b848110156128e0576002546001016000908152600b602052604090205460ff16156127f9576040516305d4bd1160e01b8152736336788a85f54d8856782d58c1ca63c7d3844531906305d4bd11906127c4906000906004016158ab565b60006040518083038186803b1580156127dc57600080fd5b505af41580156127f0573d6000803e3d6000fd5b505050506128d8565b600080612806600061395a565b9092509050600082600481111561281957fe5b14806128255750428110155b156128315750506128e0565b838061284157506104b081014210155b61285d5760405162461bcd60e51b815260040161084b9061578d565b600194508482600481111561286e57fe5b14156128815761287c61397e565b6128d5565b600282600481111561288f57fe5b141561289d5761287c613c36565b60038260048111156128ab57fe5b14156128b95761287c613eaf565b60048260048111156128c757fe5b14156128d5576128d5614128565b50505b600101612767565b50811561295c57736336788a85f54d8856782d58c1ca63c7d3844531639db74df1600061290e5a8790612ddb565b6040518363ffffffff1660e01b815260040161292b929190615ab8565b60006040518083038186803b15801561294357600080fd5b505af4158015612957573d6000803e3d6000fd5b505050505b505060016011555050565b60065490565b60019190910180546001600160a01b0319166001600160a01b03909216919091179055565b6000806000806000806000736336788a85f54d8856782d58c1ca63c7d3844531634e1eb86090918a6040518363ffffffff1660e01b81526004016129d7929190615ac6565b60606040518083038186803b1580156129ef57600080fd5b505af4158015612a03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a279190614d5f565b92509250925060008088612a3c578383612a3f565b82845b9598509650939450505050509250925092565b60606000846001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b158015612a8f57600080fd5b505afa158015612aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ac79190614d43565b6001600160a01b0316638c09166e85856040518363ffffffff1660e01b8152600401612af4929190615ac6565b60206040518083038186803b158015612b0c57600080fd5b505afa158015612b20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b449190615330565b905080604051602001612b5791906158ab565b6040516020818303038152906040529150509392505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b60208310612bec5780518252601f199092019160209182019101612bcd565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612c4e576040519150601f19603f3d011682016040523d82523d6000602084013e612c53565b606091505b5091509150818015612c81575080511580612c815750808060200190516020811015612c7e57600080fd5b50515b610e0e576040805162461bcd60e51b815260206004808301919091526024820152635448303560e01b604482015290519081900360640190fd5b600e54604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d90612ceb9084906004016158ab565b600060405180830381600087803b158015612d0557600080fd5b505af1158015612d19573d6000803e3d6000fd5b50506000808052600a602052600080516020615d2b833981519152546040519193506001600160a01b0386169250908490612d539061552a565b600060405180830381858888f193505050503d8060008114612d91576040519150601f19603f3d011682016040523d82523d6000602084013e612d96565b606091505b50509050806123455760405163032b310f60e51b815273b28c804e3dacff80701bbbafd106dbfb416a51689063656621e090611d2690600d908790879060040161588c565b6000612e0483836040518060400160405280600481526020016329a6989960e11b815250614293565b9392505050565b80820182811015612e4c576040805162461bcd60e51b81526020600480830191909152602482015263534d344560e01b604482015290519081900360640190fd5b92915050565b6000846004811115612e6057fe5b1415612e7e5760405162461bcd60e51b815260040161084b9061585f565b600042612e8f856301e13380612e0b565b1090506001856004811115612ea057fe5b14156130785760405163117d7ab160e01b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063117d7ab190612ee29084908890600401615ab8565b6101a06040518083038186803b158015612efb57600080fd5b505af4158015612f0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f339190615119565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091612f7591859190600401615ac6565b60606040518083038186803b158015612f8d57600080fd5b505af4158015612fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc59190614d5f565b9250925050600084612fdb578360e00151612fe8565b600f546001600160a01b03165b9050613004818486602001518588604001518960a0015161432b565b6130205760405162461bcd60e51b815260040161084b90615733565b851561306f57600061304585610120015186610100015161449190919063ffffffff16565b905061305182826144e6565b61306d5760405162461bcd60e51b815260040161084b906157c9565b505b505050506135dd565b600285600481111561308657fe5b141561324a57604051634ce4436960e11b8152600090736336788a85f54d8856782d58c1ca63c7d3844531906399c886d2906130c89084908890600401615ab8565b6101206040518083038186803b1580156130e157600080fd5b505af41580156130f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613119919061527b565b8051604051630270f5c360e51b8152919250600091736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613158918591600401615ac6565b60606040518083038186803b15801561317057600080fd5b505af4158015613184573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a89190614d5f565b505090506000836131bd578260a001516131ca565b600f546001600160a01b03165b90506131db82828560200151614567565b6131f75760405162461bcd60e51b815260040161084b90615733565b841561324257600061321a8460e001518560c0015161449190919063ffffffff16565b905061322682826144e6565b61306f5760405162461bcd60e51b815260040161084b906157c9565b5050506135dd565b600385600481111561325857fe5b14156134055760405163ac1ecdb360e01b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063ac1ecdb39061329a9084908890600401615ab8565b6101606040518083038186803b1580156132b357600080fd5b505af41580156132c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132eb9190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb8609161332d91859190600401615ac6565b60606040518083038186803b15801561334557600080fd5b505af4158015613359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337d9190614d5f565b9250925050600084613393578360a001516133a0565b600f546001600160a01b03165b90506133c684602001516133b457836133b6565b825b8286604001518760800151614676565b6133e25760405162461bcd60e51b815260040161084b90615733565b851561306f5760006130458560e001518660c0015161449190919063ffffffff16565b600485600481111561341357fe5b14156135dd576040516311c8197f60e01b8152600090736336788a85f54d8856782d58c1ca63c7d3844531906311c8197f906134559084908890600401615ab8565b6101606040518083038186803b15801561346e57600080fd5b505af4158015613482573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134a69190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb860916134e891859190600401615ac6565b60606040518083038186803b15801561350057600080fd5b505af4158015613514573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135389190614d5f565b925092505060008461354e578360a0015161355b565b600f546001600160a01b03165b905061356f84602001516133b457836133b6565b61358b5760405162461bcd60e51b815260040161084b90615733565b85156135d85760006135ae8560e001518660c0015161449190919063ffffffff16565b90506135ba82826144e6565b6135d65760405162461bcd60e51b815260040161084b906157c9565b505b505050505b610e0e600084614795565b8051604051630270f5c360e51b81526000918291829182918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb8609161362d91859190600401615ac6565b60606040518083038186803b15801561364557600080fd5b505af4158015613659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367d9190614d5f565b60208901516040516306c5d9cf60e41b8152939850919650945060009173b28c804e3dacff80701bbbafd106dbfb416a516891636c5d9cf0916136c891600d918a919060040161588c565b60206040518083038186803b1580156136e057600080fd5b505af41580156136f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137189190615330565b60408089015190516306c5d9cf60e41b815291925060009173b28c804e3dacff80701bbbafd106dbfb416a516891636c5d9cf09161375e91600d918a919060040161588c565b60206040518083038186803b15801561377657600080fd5b505af415801561378a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137ae9190615330565b9050866001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156137eb57600080fd5b505af11580156137ff573d6000803e3d6000fd5b5050505060e0880151604051633d2945e960e11b815273b291730099d3ac9975abd4003ba3bd47401fd2fd91637a528bd291613847918b918b908b9089908990600401615595565b604080518083038186803b15801561385e57600080fd5b505af4158015613872573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138969190615348565b9799969850949694959350505050565b81156138b7576138b7848684612b70565b8015610e0e57610e0e838683612b70565b6040516000906001600160a01b038516908390859084818181858888f193505050503d8060008114613916576040519150601f19603f3d011682016040523d82523d6000602084013e61391b565b606091505b5050905080612668576040805162461bcd60e51b815260206004808301919091526024820152632a2419a360e11b604482015290519081900360640190fd5b60008061396e8384600201546001016147c8565b90925063ffffffff169050915091565b60005a60405163a81df10f60e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d38445319063a81df10f906139be9084906004016158ab565b6101a06040518083038186803b1580156139d757600080fd5b505af41580156139eb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a0f9190615119565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613a5191859190600401615ac6565b60606040518083038186803b158015613a6957600080fd5b505af4158015613a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613aa19190614d5f565b6001600160a01b038082166000908152600a602052604080822054928516825281205493965091945090925082913091613af491613ae891906117af9062012c6c90612e0b565b61012088015190612ddb565b604051634ed4967d60e11b90613b0e908990602401615ada565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613b4c919061550e565b60006040518083038160008787f1925050503d8060008114613b8a576040519150601f19603f3d011682016040523d82523d6000602084013e613b8f565b606091505b509092509050600182613bbd57613bba8660e00151868860200151878a604001518b60a0015161432b565b90505b613bc6816147fe565b600080613be38861012001518961010001518b8b60e0015161481f565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613c239392919061569d565b60405180910390a3505050505050505050565b60005a6040516313ed2f6160e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d3844531906313ed2f6190613c769084906004016158ab565b6101206040518083038186803b158015613c8f57600080fd5b505af4158015613ca3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cc7919061527b565b905060008030613cea613cdf62012c6c61d6d8612e0b565b60e086015190612ddb565b604051631a42443160e21b90613d04908790602401615ba0565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613d42919061550e565b60006040518083038160008787f1925050503d8060008114613d80576040519150601f19603f3d011682016040523d82523d6000602084013e613d85565b606091505b509092509050600182613e3a578351604051630270f5c360e51b8152600091736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613dcf91859190600401615ac6565b60606040518083038186803b158015613de757600080fd5b505af4158015613dfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e1f9190614d5f565b50509050613e36818660a001518760200151614567565b9150505b613e43816147fe565b600080613e5e8660e001518760c00151898960a0015161481f565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613e9e9392919061569d565b60405180910390a350505050505050565b60005a604051632e9d30e160e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d384453190632e9d30e190613eef9084906004016158ab565b6101606040518083038186803b158015613f0857600080fd5b505af4158015613f1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f409190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613f8291859190600401615ac6565b60606040518083038186803b158015613f9a57600080fd5b505af4158015613fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fd29190614d5f565b9250925050600080306001600160a01b03166140316140266000600a01600089602001516140005788614002565b875b6001600160a01b0316815260208101919091526040016000205462012c6c90612e0b565b60e088015190612ddb565b604051630b65604d60e01b9061404b90899060240161587d565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614089919061550e565b60006040518083038160008787f1925050503d80600081146140c7576040519150601f19603f3d011682016040523d82523d6000602084013e6140cc565b606091505b5090925090506001826141045761410186602001516140eb57856140ed565b845b8760a0015188604001518960800151614676565b90505b61410d816147fe565b600080613be38860e001518960c001518b8b60a0015161481f565b60005a60405163a1ba139560e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d38445319063a1ba1395906141689084906004016158ab565b6101606040518083038186803b15801561418157600080fd5b505af4158015614195573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141b99190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb860916141fb91859190600401615ac6565b60606040518083038186803b15801561421357600080fd5b505af4158015614227573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061424b9190614d5f565b9250925050600080306001600160a01b03166142796140266000600a01600089602001516140005788614002565b604051633c763c1760e01b9061404b90899060240161587d565b81830381848211156143235760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156142e85781810151838201526020016142d0565b50505050905090810190601f1680156143155780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509392505050565b6001600160a01b038381166000908152600a6020526040808220549288168252812054909182918291309161435f91612e0b565b604051633ed76f1760e01b90614383908d908d908d908d908d908d906024016155cf565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516143c1919061550e565b60006040518083038160008787f1925050503d80600081146143ff576040519150601f19603f3d011682016040523d82523d6000602084013e614404565b606091505b50915091508161448557876001600160a01b0316896001600160a01b0316600080516020615d0b8339815191528984604051614441929190615c17565b60405180910390a3856001600160a01b0316896001600160a01b0316600080516020615d0b833981519152878460405161447c929190615c17565b60405180910390a35b50979650505050505050565b60008115806144ac575050808202828282816144a957fe5b04145b612e4c576040805162461bcd60e51b81526020600480830191909152602482015263534d324160e01b604482015290519081900360640190fd5b6000816144f557506001612e4c565b60008052600a602052600080516020615d2b8339815191525461451b90849084906148af565b9050801515836001600160a01b03167fdbef2fc26e7694e7a1c5a4801b1ad144136d149cf76f310a780689b4087f0ffe8460405161455991906158ab565b60405180910390a392915050565b60008161457657506001612e04565b600080306001600160a01b031661d6d863c9cd976060e01b88888860006040516024016145a69493929190615609565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516145e4919061550e565b60006040518083038160008787f1925050503d8060008114614622576040519150601f19603f3d011682016040523d82523d6000602084013e614627565b606091505b50915091508161466d57856001600160a01b0316856001600160a01b0316600080516020615d0b8339815191528684604051614664929190615c17565b60405180910390a35b50949350505050565b6000826146855750600161478d565b6001600160a01b0385166000908152600a60205260408082205490518291309163e5b1be6560e01b906146c2908b908b908b908b90602401615609565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614700919061550e565b60006040518083038160008787f1925050503d806000811461473e576040519150601f19603f3d011682016040523d82523d6000602084013e614743565b606091505b50915091508161478957866001600160a01b0316866001600160a01b0316600080516020615d0b8339815191528784604051614780929190615c17565b60405180910390a35b5090505b949350505050565b6000908152600391820160205260408120818155600181018290556002810180546001600160e81b031916905590910155565b60008181526003830160205260408120805463ffffffff610100820416919060ff166147f38161490d565b935050509250929050565b806148125761480d600061497d565b61481c565b61481c60006149d0565b50565b6000808061482d8787614491565b90506148406155946117af5a8890612ddb565b92506000614865826148606000600601548761449190919063ffffffff16565b614a07565b90506148718282612ddb565b925061487d33826144e6565b6148995760405162461bcd60e51b815260040161084b906157c9565b6148a385846144e6565b50505094509492505050565b6040516000906001600160a01b038516908390859084818181858888f193505050503d80600081146148fd576040519150601f19603f3d011682016040523d82523d6000602084013e614902565b606091505b509095945050505050565b6000600182141561492057506001610eab565b600282141561493157506002610eab565b600382141561494257506004610eab565b600482141561495357506004610eab565b600582141561496457506003610eab565b600682141561497557506003610eab565b506000919050565b600281015460009081526003820160205260409020805465010000000000900460ff16156149ac5760036149af565b60025b815460ff91909116650100000000000265ff00000000001990911617905550565b60028082015460009081526003928301602052604081208181556001810182905591820180546001600160e81b0319169055910155565b6000818310614a165781612e04565b5090919050565b604051806101200160405280600063ffffffff16815260200160008152602001600081526020016000815260200160001515815260200160006001600160a01b031681526020016000815260200160008152602001600063ffffffff1681525090565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b604051806101a00160405280600063ffffffff1681526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160006001600160a01b031681526020016000815260200160008152602001600063ffffffff16815260200160008152602001600063ffffffff1681525090565b8035610eab81615cc8565b8051610eab81615cc8565b8035610eab81615cdd565b8051610eab81615cdd565b6000610160808385031215614ba2578182fd5b614bab81615c78565b915050614bb782614d11565b8152614bc560208301614b79565b60208201526040820135604082015260608201356060820152614bea60808301614b79565b6080820152614bfb60a08301614b63565b60a082015260c082013560c082015260e082013560e0820152610100614c22818401614d11565b908201526101208281013590820152610140614c3f818401614d11565b9082015292915050565b6000610160808385031215614c5c578182fd5b614c6581615c78565b915050614c7182614d1c565b8152614c7f60208301614b84565b60208201526040820151604082015260608201516060820152614ca460808301614b84565b6080820152614cb560a08301614b6e565b60a082015260c082015160c082015260e082015160e0820152610100614cdc818401614d1c565b908201526101208281015190820152610140614c3f818401614d1c565b60006101008284031215614d0b578081fd5b50919050565b8035610eab81615cf8565b8051610eab81615cf8565b600060208284031215614d38578081fd5b8135612e0481615cc8565b600060208284031215614d54578081fd5b8151612e0481615cc8565b600080600060608486031215614d73578182fd5b8351614d7e81615cc8565b6020850151909350614d8f81615cc8565b6040850151909250614da081615cc8565b809150509250925092565b600080600060608486031215614dbf578081fd5b8335614dca81615cc8565b92506020840135614dda81615cc8565b929592945050506040919091013590565b60008060008060008060c08789031215614e03578384fd5b8635614e0e81615cc8565b95506020870135614e1e81615cc8565b9450604087013593506060870135614e3581615cc8565b92506080870135915060a0870135614e4c81615cdd565b809150509295509295509295565b60008060008060808587031215614e6f578182fd5b8435614e7a81615cc8565b93506020850135614e8a81615cc8565b9250604085013591506060850135614ea181615cdd565b939692955090935050565b60008060408385031215614ebe578182fd5b8235614ec981615cc8565b91506020830135614ed981615cdd565b809150509250929050565b600080600060608486031215614ef8578081fd5b8335614f0381615cc8565b92506020840135614f1381615ceb565b91506040840135614da081615cdd565b60008060408385031215614f35578182fd5b8235614f4081615cc8565b946020939093013593505050565b600060208284031215614f5f578081fd5b8151612e0481615cdd565b60008060008060808587031215614f7f578182fd5b8451614f8a81615cdd565b60208601516040870151606090970151919890975090945092505050565b600060208284031215614fb9578081fd5b815160068110612e04578182fd5b60008060408385031215614fd9578182fd5b8251614fe481615ceb565b6020840151909250614ed981615cf8565b60006101608284031215615007578081fd5b612e048383614b8f565b60006101608284031215615023578081fd5b612e048383614c49565b6000610100828403121561503f578081fd5b612e048383614cf9565b60006101a080838503121561505c578182fd5b61506581615c78565b905061507083614d11565b8152602083013560208201526040830135604082015260608301356060820152608083013560808201526150a660a08401614b79565b60a08201526150b760c08401614b79565b60c08201526150c860e08401614b63565b60e0820152610100838101359082015261012080840135908201526101406150f1818501614d11565b90820152610160838101359082015261018061510e818501614d11565b908201529392505050565b60006101a080838503121561512c578182fd5b61513581615c78565b905061514083614d1c565b81526020830151602082015260408301516040820152606083015160608201526080830151608082015261517660a08401614b84565b60a082015261518760c08401614b84565b60c082015261519860e08401614b6e565b60e0820152610100838101519082015261012080840151908201526101406151c1818501614d1c565b90820152610160838101519082015261018061510e818501614d1c565b60006101608284031215614d0b578081fd5b6000610120808385031215615203578182fd5b61520c81615c78565b905061521783614d11565b815260208301356020820152604083013560408201526060830135606082015261524360808401614b79565b608082015261525460a08401614b63565b60a082015260c083013560c082015260e083013560e082015261010061510e818501614d11565b600061012080838503121561528e578182fd5b61529781615c78565b90506152a283614d1c565b81526020830151602082015260408301516040820152606083015160608201526152ce60808401614b84565b60808201526152df60a08401614b6e565b60a082015260c083015160c082015260e083015160e082015261010061510e818501614d1c565b60006101208284031215614d0b578081fd5b600060208284031215615329578081fd5b5035919050565b600060208284031215615341578081fd5b5051919050565b6000806040838503121561535a578182fd5b505080516020909101519092909150565b60006020828403121561537c578081fd5b8135612e0481615cf8565b6001600160a01b03169052565b15159052565b600081518084526153b2816020860160208601615c9c565b601f01601f19169290920160200192915050565b600581106153d057fe5b9052565b6153df828251615504565b60208101516153f16020840182615394565b50604081015160408301526060810151606083015260808101516154186080840182615394565b5060a081015161542b60a0840182615387565b5060c081015160c083015260e081015160e08301526101008082015161545382850182615504565b505061012081810151908301526101408082015161266882850182615504565b803561547e81615cc8565b6001600160a01b03908116835260208201359061549a82615cc8565b166020830152604081810135908301526060808201359083015260808101356154c281615cdd565b1515608083015260a08101356154d781615cc8565b6154e460a0840182615387565b5060c081013560c08301526154fb60e08201614d11565b61234560e08401825b63ffffffff169052565b60008251615520818460208701615c9c565b9190910192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039687168152948616602086015292851660408501529084166060840152909216608082015260a081019190915260c00190565b6001600160a01b0396871681529486166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b6001600160a01b0396871681529486166020860152604085019390935293166060830152608082019290925290151560a082015260c00190565b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061566c9083018461539a565b979650505050505050565b6001600160a01b039290921682521515602082015260400190565b901515815260200190565b6000606082526156b0606083018661539a565b60208301949094525060400152919050565b60208101600683106156d057fe5b91905290565b604081016156e482856153c6565b63ffffffff831660208301529392505050565b6020808252600490820152632a22181b60e11b604082015260600190565b6020808252600490820152635444314360e01b604082015260600190565b60208082526004908201526315110c4d60e21b604082015260600190565b6020808252600490820152635444303360e01b604082015260600190565b6020808252600490820152635444333760e01b604082015260600190565b6020808252600490820152630544430360e41b604082015260600190565b6020808252600490820152635444303160e01b604082015260600190565b6020808252600490820152630544434360e41b604082015260600190565b60208082526004908201526315110c0d60e21b604082015260600190565b6020808252600490820152632a221a9960e11b604082015260600190565b6020808252600490820152632a22181960e11b604082015260600190565b6020808252600490820152630a88860760e31b604082015260600190565b6020808252600490820152635444343160e01b604082015260600190565b6101608101612e4c82846153d4565b9283526001600160a01b03919091166020830152604082015260600190565b90815260200190565b9182526001600160a01b0316602082015260400190565b8481526001600160a01b0384166020820152608081016158ee60408301856153c6565b821515606083015295945050505050565b83815261014081016159146020830185615473565b82610120830152949350505050565b8381526101a081016159406020830161593b86614b63565b615387565b61594c60208501614b63565b6159596040840182615387565b506040840135606083015260608401356080830152608084013560a083015260a084013560c083015261598e60c08501614b79565b61599b60e0840182615394565b506159a860e08501614b79565b6101006159b781850183615394565b6159c2818701614b63565b9150506101206159d481850183615387565b61014091508086013582850152506159ed818601614d11565b90506159fd610160840182615504565b5082610180830152949350505050565b8281526101408101615a256020830161593b85614b63565b615a3160208401614b63565b615a3e6040840182615387565b506040830135606083015260608301356080830152608083013560a0830152615a6960a08401614b79565b615a7660c0840182615394565b50615a8360c08401614b63565b615a9060e0840182615387565b5061010060e084013581840152615aa8818501614d11565b9050614323610120840182615504565b918252602082015260400190565b91825263ffffffff16602082015260400190565b60006101a082019050615aee828451615504565b6020830151602083015260408301516040830152606083015160608301526080830151608083015260a0830151615b2860a0840182615394565b5060c0830151615b3b60c0840182615394565b5060e0830151615b4e60e0840182615387565b506101008381015190830152610120808401519083015261014080840151615b7882850182615504565b5050610160838101519083015261018080840151615b9882850182615504565b505092915050565b60006101208201905063ffffffff835116825260208301516020830152604083015160408301526060830151606083015260808301511515608083015260a0830151615bef60a0840182615387565b5060c083015160c083015260e083015160e083015261010080840151615b9882850182615504565b60008382526040602083015261478d604083018461539a565b600085825284602083015260018060a01b038416604083015260806060830152615c5d608083018461539a565b9695505050505050565b63ffffffff91909116815260200190565b60405181810167ffffffffffffffff81118282101715615c9457fe5b604052919050565b60005b83811015615cb7578181015183820152602001615c9f565b838111156126685750506000910152565b6001600160a01b038116811461481c57600080fd5b801515811461481c57600080fd5b6005811061481c57600080fd5b63ffffffff8116811461481c57600080fdfe786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b21159213da86008ba1c6922daee3e07db95305ef49ebced9f5467a0b8613fcc6b343e3a26469706673582212204869fe8a86a81d32e462924c6375438fb998a95decb6fe160a341c323c1eee6f64736f6c63430007060033

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

000000000000000000000000c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c6000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000003a1d749fa4a9e650fce844ff1c58c5faf7e2a9d1

-----Decoded View---------------
Arg [0] : _factory (address): 0xC480b33eE5229DE3FbDFAD1D2DCD3F3BAD0C56c6
Arg [1] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [2] : _bot (address): 0x3a1D749fa4a9E650FCe844fF1C58C5faf7e2a9D1

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c6
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [2] : 0000000000000000000000003a1d749fa4a9e650fce844ff1c58c5faf7e2a9d1


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

OVERVIEW

The Delay contract of Integral SIZE.

Validator Index Block Amount
View All Withdrawals

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

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