Contract 0x7b96662d4dbbf6894a888ba53afbe2f98359c973

 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2acExecute432308662022-12-03 10:44:081 day 2 hrs ago0x90779545ffbef2e2a2e897b3db7b1d36c05c9e70 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730 ETH0.00005425
0xb0e9a754d95c7bb1c9c41f088ee44722792d89ed8903303239095920b8377930Execute432251412022-12-03 10:16:201 day 2 hrs ago0x90779545ffbef2e2a2e897b3db7b1d36c05c9e70 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730 ETH0.0000465
0x690ef82d7ad9d5073ae4011e4507e85c02e9465fd638fc87f4dce0a5ab2afd4fDeposit432245422022-12-03 10:13:351 day 2 hrs ago0xdd5d3ac28853613300438ec9f3af370b202a449a IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730.00116879009149 ETH0.00094848
0x68b1994799ad395d15dcea2812bc4358256c10463f9dfb4c8b515fad57a13ff8Sell432185072022-12-03 9:45:481 day 3 hrs ago0x2214541b2bbce7b3e2d7b6a48bcdbda914e09105 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730.00084 ETH0.00083717
0x549a43ff318bfb19ac71011e0f4f4b5996f70dd6fd4abb5a30f285dc4159668dExecute431007812022-12-02 22:27:331 day 14 hrs ago0x90779545ffbef2e2a2e897b3db7b1d36c05c9e70 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730 ETH0.00005688
0x8fd7d5a872760ee276e65cffd34d242d95a4dc7aba81226bbe53c0a31093d271Deposit430956432022-12-02 21:57:061 day 14 hrs ago0xe462053d2fb0630b3336d9518adaace4f0657b2c IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730.001099397394089 ETH0.00007509
0x4e83923a87f52cb1181675f48f6b4c93a64b8e77424cd8141e656d680edc697eExecute430687262022-12-02 19:37:131 day 17 hrs ago0x90779545ffbef2e2a2e897b3db7b1d36c05c9e70 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730 ETH0.00004805
0x972c2e2818e5ca12d2ae2dce77784851a8f1724411b6a951433e515a6f0f82d1Sell430624702022-12-02 19:06:441 day 17 hrs ago0xe462053d2fb0630b3336d9518adaace4f0657b2c IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730.00094 ETH0.00099411
0x125e285697238d1041964111984fef06fafebec9cdda93ef15edbf863ee33569Execute430254132022-12-02 16:02:431 day 20 hrs ago0x90779545ffbef2e2a2e897b3db7b1d36c05c9e70 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730 ETH0.00005019
0x25ab6fab27b612c5b433eb2274f634fb0812f2273cf57f3663b88de3de311880Execute430242462022-12-02 15:57:061 day 20 hrs ago0x90779545ffbef2e2a2e897b3db7b1d36c05c9e70 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730 ETH0.00006341
0x7c89a502549aea545cbf7b428e5eb31f8fb49380a5b1a1bab9c923f9d6ee97f3Execute430224292022-12-02 15:48:281 day 21 hrs ago0x90779545ffbef2e2a2e897b3db7b1d36c05c9e70 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730 ETH0.00005434
0x957ce43731a0a634100a416d3073d042ede7b6c97e867320fba155ed17bfacf4Sell430190052022-12-02 15:32:131 day 21 hrs ago0x1be693074c32541919bba91ac873464a29c09d68 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730.00094 ETH0.0011715
0x744aac9fb9b02bfec2854feff24cad52875c9e0cba09dd8fe9ea48679667ea4bDeposit430178012022-12-02 15:26:351 day 21 hrs ago0x1be693074c32541919bba91ac873464a29c09d68 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730.001097063609145 ETH0.0013586
0x12d16f07f54e19d88e13a7e196012337cdd735dcdccaea8fbd971940fa3f8019Sell430160232022-12-02 15:17:561 day 21 hrs ago0xb2ffa393f0b4072081eb2738eb8340bf877bae38 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730.00084 ETH0.00007348
0xa50b5b0077a8a035a14a1cd0282d8f89b876b3e1ea7f9e4c7766428995b0f00bExecute429000932022-12-02 6:14:452 days 6 hrs ago0x90779545ffbef2e2a2e897b3db7b1d36c05c9e70 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730 ETH0.000045
0x14152dea404e11c63d642acd2287a18933da72dcb80f48533f547098709a7025Sell428948472022-12-02 5:44:172 days 7 hrs ago0xe8b65b125afd293cdb2b496c4035ebf63e4d56a9 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730.00084 ETH0.00088814
0x5060077bc4cf997cad67bf9bf72473041ce2afd976d9412a715941ecd641a7f9Execute428932472022-12-02 5:33:562 days 7 hrs ago0x90779545ffbef2e2a2e897b3db7b1d36c05c9e70 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730 ETH0.00004441
0x29a1700428d10809c28f57ac889ee7e125fa87f96f435273ff59b25667ee99f6Sell428883832022-12-02 5:03:262 days 7 hrs ago0xe8b65b125afd293cdb2b496c4035ebf63e4d56a9 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730.01734 ETH0.00087361
0x515f372b45e12c0cc9a52dd178cc44085cd398f680ea7669ac194ace5993d6a6Execute427028152022-12-01 12:39:143 days 14 mins ago0x90779545ffbef2e2a2e897b3db7b1d36c05c9e70 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730 ETH0.00004878
0x98cadb632a31b2b9a6554e37d8902945f08adb87b324cc06fc1448d0112d8512Buy426962922022-12-01 12:08:443 days 45 mins ago0x62eec9d41c2b2f175db9c65ba45776d530c47450 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730.190265612157231 ETH0.00005456
0xf347a2484477f03b97922f07e62df4312d48c92ab80b075db2b8fffd710a76c5Execute426959242022-12-01 12:07:023 days 46 mins ago0x90779545ffbef2e2a2e897b3db7b1d36c05c9e70 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730 ETH0.00004689
0xa46f335df493c588e9184063b7c5852d0c118f8e533c09515a1a58b740ad5aa1Sell426892352022-12-01 11:36:333 days 1 hr ago0x62eec9d41c2b2f175db9c65ba45776d530c47450 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730.00084 ETH0.00005726
0x479081c02f0678ce60437adaa7e0a417709ad0277a529e54476cd38b8237a4b0Execute425322742022-11-30 20:10:533 days 16 hrs ago0x90779545ffbef2e2a2e897b3db7b1d36c05c9e70 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730 ETH0.00006601
0x2cd50998ba275f3723d68bab0210733867b76629481949d5d2263a73122e9207Deposit425265752022-11-30 19:40:183 days 17 hrs ago0xecac15b131de8bd23f56ae34dd68febdada375e4 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730.001165931903755 ETH0.00142302
0x666438ea8255ebde03d08a076a5a9bf2a122b4be3b79b52812705543cb767b4dExecute425263262022-11-30 19:39:003 days 17 hrs ago0x90779545ffbef2e2a2e897b3db7b1d36c05c9e70 IN  0x7b96662d4dbbf6894a888ba53afbe2f98359c9730 ETH0.00006597
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x0edc96c6070fef121cb4a1af50fc8e02fe6a84860 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c9730xdd5d3ac28853613300438ec9f3af370b202a449a0.0000232711 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c9730x90779545ffbef2e2a2e897b3db7b1d36c05c9e700.0000417289 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0xff970a61a04b1ca14834a43f5de4533ebddb5cc80 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x4bca34ad27df83566016b55c60dd80a9eb14913b0 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0xff970a61a04b1ca14834a43f5de4533ebddb5cc80 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x82af49447d8a07e3bd95bd0d56f35241523fbab10 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x4bca34ad27df83566016b55c60dd80a9eb14913b0 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x4bca34ad27df83566016b55c60dd80a9eb14913b0 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0xa1f563cc7da98a87983aec5d5d3dfdb53ef4c9740 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x4bca34ad27df83566016b55c60dd80a9eb14913b0 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0xff970a61a04b1ca14834a43f5de4533ebddb5cc80 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x635e1edea94eda4afcb5ec404c029257ceecf0640 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x4bca34ad27df83566016b55c60dd80a9eb14913b0 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x4bca34ad27df83566016b55c60dd80a9eb14913b0 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x4bca34ad27df83566016b55c60dd80a9eb14913b0 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0xa1f563cc7da98a87983aec5d5d3dfdb53ef4c9740 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x635e1edea94eda4afcb5ec404c029257ceecf0640 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x4bca34ad27df83566016b55c60dd80a9eb14913b0 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x4bca34ad27df83566016b55c60dd80a9eb14913b0 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0xff970a61a04b1ca14834a43f5de4533ebddb5cc80 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x82af49447d8a07e3bd95bd0d56f35241523fbab10 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x4bca34ad27df83566016b55c60dd80a9eb14913b0 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0x4bca34ad27df83566016b55c60dd80a9eb14913b0 ETH
0xd9d49083bee7e542e92b4f006e48755eb7f1f5b18a3d4cea88bd9d9f5e4fc2ac432308662022-12-03 10:44:081 day 2 hrs ago 0x7b96662d4dbbf6894a888ba53afbe2f98359c973 0xa1f563cc7da98a87983aec5d5d3dfdb53ef4c9740 ETH
[ Download CSV Export 
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
TwapDelay

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 16 : 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;
    uint16 private constant MAX_TOLERANCE = 10;

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

    mapping(address => uint16) public override tolerance;

    constructor(
        address _factory,
        address _weth,
        address _bot
    ) {
        orders.factory = _factory;
        owner = msg.sender;
        isBot[_bot] = true;
        orders.gasPrice = tx.gasprice - (tx.gasprice % 1e6);
        tokenShares.weth = _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) {
        (order, , ) = 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) {
        (order, ) = orders.getSellOrder(orderId);
    }

    function getBuyOrder(uint256 orderId) external view override returns (Orders.BuyOrder memory order) {
        (order, ) = 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 locked;
    modifier lock() {
        require(locked == 0, 'TD06');
        locked = 1;
        _;
        locked = 0;
    }

    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 payable override {
        require(msg.sender == owner, 'TD00');
        orders.setOrderDisabled(pair, orderType, disabled);
    }

    function setOwner(address _owner) external payable override {
        require(msg.sender == owner, 'TD00');
        // require(_owner != owner, 'TD01'); // Comment out to save size
        require(_owner != address(0), 'TD02');
        owner = _owner;
        emit OwnerSet(_owner);
    }

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

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

    function setDelay(uint32 _delay) external payable override {
        require(msg.sender == owner, 'TD00');
        // require(_delay != orders.delay, 'TD01'); // Comment out to save size
        orders.delay = _delay;
        emit DelaySet(_delay);
    }

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

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

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

    function setTolerance(address pair, uint16 amount) external payable override {
        require(msg.sender == owner, 'TD00');
        require(amount <= MAX_TOLERANCE, 'TD54');
        tolerance[pair] = amount;
        emit ToleranceSet(pair, amount);
    }

    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 payable override lock {
        emit Execute(msg.sender, n);
        uint256 gasBefore = gasleft();
        bool orderExecuted;
        bool senderCanExecute = isBot[msg.sender] || isBot[address(0)];
        for (uint256 i; 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, uint256 amountLimit0, uint256 amountLimit1) = 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, amountLimit0, amountLimit1));
        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 = Orders.refundLiquidity(
                pair,
                withdrawOrder.to,
                withdrawOrder.liquidity,
                this._refundLiquidity.selector
            );
        }
        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, uint256 amountLimit) = 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, amountLimit));
        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, uint256 amountLimit) = 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, amountLimit));
        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 payable {
        // 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 payable {
        require(msg.sender == address(this), 'TD00');
        if (token == tokenShares.weth && unwrap) {
            uint256 amount = tokenShares.sharesToAmount(token, share, 0, to);
            IWETH(tokenShares.weth).withdraw(amount);
            TransferHelper.safeTransferETH(to, amount, orders.transferGasCosts[address(0)]);
        } else {
            TransferHelper.safeTransfer(token, to, tokenShares.sharesToAmount(token, share, 0, to));
        }
    }

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

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

        (
            Orders.PairInfo memory pairInfo,
            uint256 amount0Left,
            uint256 amount1Left,
            uint256 swapToken
        ) = _initialDeposit(depositOrder, amountLimit0, amountLimit1);
        if (depositOrder.swap && swapToken != 0) {
            bytes memory data = encodePriceInfo(pairInfo.pair, depositOrder.priceAccumulator, depositOrder.timestamp);
            if (amount0Left != 0 && swapToken == 1) {
                uint256 extraAmount1;
                (amount0Left, extraAmount1) = AddLiquidity.swapDeposit0(
                    pairInfo.pair,
                    pairInfo.token0,
                    amount0Left,
                    depositOrder.minSwapPrice,
                    tolerance[pairInfo.pair],
                    data
                );
                amount1Left = amount1Left.add(extraAmount1);
            } else if (amount1Left != 0 && swapToken == 2) {
                uint256 extraAmount0;
                (extraAmount0, amount1Left) = AddLiquidity.swapDeposit1(
                    pairInfo.pair,
                    pairInfo.token1,
                    amount1Left,
                    depositOrder.maxSwapPrice,
                    tolerance[pairInfo.pair],
                    data
                );
                amount0Left = amount0Left.add(extraAmount0);
            }
        }

        if (amount0Left != 0 && amount1Left != 0) {
            (amount0Left, amount1Left, ) = AddLiquidity.addLiquidityAndMint(
                pairInfo.pair,
                depositOrder.to,
                pairInfo.token0,
                pairInfo.token1,
                amount0Left,
                amount1Left
            );
        }

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

    function _initialDeposit(
        Orders.DepositOrder calldata depositOrder,
        uint256 amountLimit0,
        uint256 amountLimit1
    )
        private
        returns (
            Orders.PairInfo memory pairInfo,
            uint256 amount0Left,
            uint256 amount1Left,
            uint256 swapToken
        )
    {
        pairInfo = orders.pairs[depositOrder.pairId];
        uint256 amount0Desired = tokenShares.sharesToAmount(
            pairInfo.token0,
            depositOrder.share0,
            amountLimit0,
            depositOrder.to
        );
        uint256 amount1Desired = tokenShares.sharesToAmount(
            pairInfo.token1,
            depositOrder.share1,
            amountLimit1,
            depositOrder.to
        );
        ITwapPair(pairInfo.pair).sync();
        (amount0Left, amount1Left, swapToken) = AddLiquidity.addLiquidityAndMint(
            pairInfo.pair,
            depositOrder.to,
            pairInfo.token0,
            pairInfo.token1,
            amount0Desired,
            amount1Desired
        );
    }

    function _executeWithdraw(Orders.WithdrawOrder calldata withdrawOrder) external payable {
        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;
        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 calldata buyOrder, uint256 amountLimit) external payable {
        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, amountLimit, buyOrder.to);
        ITwapPair(pairAddress).sync();
        bytes memory priceInfo = encodePriceInfo(pairAddress, buyOrder.priceAccumulator, buyOrder.timestamp);
        uint256 amountIn;
        uint256 amountOut;
        uint256 reserveOut;
        {
            // scope for reserve out logic, avoids stack too deep errors
            (uint112 reserve0, uint112 reserve1) = ITwapPair(pairAddress).getReserves();
            // subtract 1 to prevent reserve going to 0
            reserveOut = uint256(buyOrder.inverse ? reserve0 : reserve1).sub(1);
        }
        {
            // scope for partial fill logic, avoids stack too deep errors
            address oracle = ITwapPair(pairAddress).oracle();
            uint256 swapFee = ITwapPair(pairAddress).swapFee();
            (amountIn, amountOut) = ITwapOracle(oracle).getSwapAmountInMaxOut(
                buyOrder.inverse,
                swapFee,
                buyOrder.amountOut,
                priceInfo
            );
            uint256 amountInMaxScaled;
            if (amountOut > reserveOut) {
                amountInMaxScaled = amountInMax.mul(reserveOut).ceil_div(buyOrder.amountOut);
                (amountIn, amountOut) = ITwapOracle(oracle).getSwapAmountInMinOut(
                    buyOrder.inverse,
                    swapFee,
                    reserveOut,
                    priceInfo
                );
            } else {
                amountInMaxScaled = amountInMax;
                amountOut = buyOrder.amountOut; // Truncate to desired out
            }
            require(amountInMaxScaled >= 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));
                }
            }
            TransferHelper.safeTransfer(tokenIn, pairAddress, amountIn);
        }
        amountOut = amountOut.sub(tolerance[pairAddress]);
        uint256 amount0Out;
        uint256 amount1Out;
        if (buyOrder.inverse) {
            amount0Out = amountOut;
        } else {
            amount1Out = amountOut;
        }
        if (tokenOut == tokenShares.weth && buyOrder.unwrap) {
            ITwapPair(pairAddress).swap(amount0Out, amount1Out, address(this), priceInfo);
            _forceEtherTransfer(buyOrder.to, amountOut);
        } else {
            ITwapPair(pairAddress).swap(amount0Out, amount1Out, buyOrder.to, priceInfo);
        }
    }

    function _executeSell(Orders.SellOrder calldata sellOrder, uint256 amountLimit) external payable {
        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
        );
        ITwapPair(pairAddress).sync();
        bytes memory priceInfo = encodePriceInfo(pairAddress, sellOrder.priceAccumulator, sellOrder.timestamp);

        uint256 amountOut = _executeSellHelper(sellOrder, amountLimit, pairAddress, tokenIn, priceInfo);

        (uint256 amount0Out, uint256 amount1Out) = sellOrder.inverse
            ? (amountOut, uint256(0))
            : (uint256(0), amountOut);
        if (tokenOut == tokenShares.weth && sellOrder.unwrap) {
            ITwapPair(pairAddress).swap(amount0Out, amount1Out, address(this), priceInfo);
            _forceEtherTransfer(sellOrder.to, amountOut);
        } else {
            ITwapPair(pairAddress).swap(amount0Out, amount1Out, sellOrder.to, priceInfo);
        }
    }

    function _executeSellHelper(
        Orders.SellOrder calldata sellOrder,
        uint256 amountLimit,
        address pairAddress,
        address tokenIn,
        bytes memory priceInfo
    ) internal returns (uint256 amountOut) {
        uint256 reserveOut;
        {
            // scope for determining reserve out, avoids stack too deep errors
            (uint112 reserve0, uint112 reserve1) = ITwapPair(pairAddress).getReserves();
            // subtract 1 to prevent reserve going to 0
            reserveOut = uint256(sellOrder.inverse ? reserve0 : reserve1).sub(1);
        }
        {
            // scope for calculations, avoids stack too deep errors
            address oracle = ITwapPair(pairAddress).oracle();
            uint256 swapFee = ITwapPair(pairAddress).swapFee();
            uint256 amountIn = tokenShares.sharesToAmount(tokenIn, sellOrder.shareIn, amountLimit, sellOrder.to);
            amountOut = sellOrder.inverse
                ? ITwapOracle(oracle).getSwapAmount0Out(swapFee, amountIn, priceInfo)
                : ITwapOracle(oracle).getSwapAmount1Out(swapFee, amountIn, priceInfo);

            uint256 amountOutMinScaled;
            if (amountOut > reserveOut) {
                amountOutMinScaled = sellOrder.amountOutMin.mul(reserveOut).div(amountOut);
                uint256 _amountIn = amountIn;
                (amountIn, amountOut) = ITwapOracle(oracle).getSwapAmountInMinOut(
                    sellOrder.inverse,
                    swapFee,
                    reserveOut,
                    priceInfo
                );
                if (tokenIn == tokenShares.weth && sellOrder.unwrap) {
                    _forceEtherTransfer(sellOrder.to, _amountIn.sub(amountIn));
                } else {
                    TransferHelper.safeTransfer(tokenIn, sellOrder.to, _amountIn.sub(amountIn));
                }
            } else {
                amountOutMinScaled = sellOrder.amountOutMin;
            }
            amountOut = amountOut.sub(tolerance[pairAddress]);
            require(amountOut >= amountOutMinScaled, 'TD37');
            TransferHelper.safeTransfer(tokenIn, pairAddress, amountIn);
        }
    }

    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) {
                require(refundEth(payable(to), depositOrder.gasPrice.mul(depositOrder.gasLimit)), '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(Orders.refundLiquidity(pair, to, withdrawOrder.liquidity, this._refundLiquidity.selector), 'TD14');
            if (shouldRefundEth) {
                require(refundEth(payable(to), withdrawOrder.gasPrice.mul(withdrawOrder.gasLimit)), '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) {
                require(refundEth(payable(to), sellOrder.gasPrice.mul(sellOrder.gasLimit)), '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) {
                require(refundEth(payable(to), buyOrder.gasPrice.mul(buyOrder.gasLimit)), '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 16 : 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 3 of 16 : 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 ToleranceSet(address pair, uint16 amount);
    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 tolerance(address pair) external returns (uint16);

    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 view returns (Orders.OrderStatus);

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

    function setOwner(address _owner) external payable;

    function setBot(address _bot, bool _isBot) external payable;

    function setMaxGasLimit(uint256 _maxGasLimit) external payable;

    function setDelay(uint32 _delay) external payable;

    function setGasPriceInertia(uint256 _gasPriceInertia) external payable;

    function setMaxGasPriceImpact(uint256 _maxGasPriceImpact) external payable;

    function setTransferGasCost(address token, uint256 gasCost) external payable;

    function setTolerance(address pair, uint16 amount) external payable;

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

    function retryRefund(uint256 orderId) external;

    function cancelOrder(uint256 orderId) external;
}

File 4 of 16 : 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');
        return a / b;
    }

    function ceil_div(uint256 a, uint256 b) internal pure returns (uint256 c) {
        c = div(a, b);
        if (a != mul(b, c)) {
            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 c) {
        c = a + b;
        require((b >= 0 && c >= a) || (b < 0 && c < a), 'SM4D');
    }

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

    function mul(int256 a, int256 b) internal pure returns (int256 c) {
        // 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');

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

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

        return a / b;
    }

    function neg_floor_div(int256 a, int256 b) internal pure returns (int256 c) {
        c = div(a, b);
        if ((a < 0 && b > 0) || (a >= 0 && b < 0)) {
            if (a != mul(b, c)) {
                c = sub(c, 1);
            }
        }
    }
}

File 5 of 16 : 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);

    event RefundFailed(address indexed to, address indexed token, uint256 amount, bytes data);

    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;
        // slot4
        uint112 amountLimit0;
        uint112 amountLimit1;
    }

    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)
        internal
        view
        returns (OrderType orderType, uint32 validAfterTimestamp)
    {
        StoredOrder storage order = data.orderQueue[orderId];
        validAfterTimestamp = order.validAfterTimestamp;
        orderType = decodeType(order.orderType);
    }

    function getOrderStatus(Data storage data, uint256 orderId) internal 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)
        internal
        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) internal view returns (bool) {
        return data.orderDisabled[pair] & DEPOSIT_MASK != 0;
    }

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

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

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

    function getDepositOrder(Data storage data, uint256 index)
        public
        view
        returns (
            DepositOrder memory order,
            uint256 amountLimit0,
            uint256 amountLimit1
        )
    {
        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;

        amountLimit0 = stored.amountLimit0;
        amountLimit1 = stored.amountLimit1;
    }

    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, uint256 amountLimit)
    {
        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;

        amountLimit = stored.amountLimit0;
    }

    function getBuyOrder(Data storage data, uint256 index)
        public
        view
        returns (BuyOrder memory order, uint256 amountLimit)
    {
        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;

        amountLimit = stored.amountLimit0;
    }

    function getFailedOrderType(Data storage data, uint256 orderId)
        internal
        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 < 1 << 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 < 256 - 24; ++exponent) {
            // Last bit is one.
            if (number & 1 == 1) {
                break;
            }
            number = number >> 1;
        }
        // The number must fit in the mantissa.
        require(number < 1 << 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,
        uint256 amountIn0,
        uint256 amountIn1
    ) 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,
            amountIn0.toUint112(),
            amountIn1.toUint112()
        );
    }

    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
            0, // amountLimit0
            0 // amountLimit1
        );
    }

    function enqueueSellOrder(
        Data storage data,
        SellOrder memory sellOrder,
        uint256 amountIn
    ) 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,
            amountIn.toUint112(),
            0 // amountLimit1
        );
    }

    function enqueueBuyOrder(
        Data storage data,
        BuyOrder memory buyOrder,
        uint256 amountInMax
    ) 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,
            amountInMax.toUint112(),
            0 // amountLimit1
        );
    }

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

    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 {
        {
            // scope for checks, avoids stack too deep errors
            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 = msg.value.sub(depositParams.amount0, 'OS1E');
                } else if (depositParams.token1 == tokenShares.weth) {
                    value = msg.value.sub(depositParams.amount1, 'OS1E');
                }
            }
            allocateGasRefund(data, value, depositParams.gasLimit);
        }

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

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

    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 = msg.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
            ),
            sellParams.amountIn
        );
    }

    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 = msg.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
            ),
            buyParams.amountInMax
        );
    }

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

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

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

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

    function dequeueDepositOrder(Data storage data)
        external
        returns (
            DepositOrder memory order,
            uint256 amountLimit0,
            uint256 amountLimit1
        )
    {
        ++data.lastProcessedOrderId;
        (order, amountLimit0, amountLimit1) = 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, uint256 amountLimit) {
        ++data.lastProcessedOrderId;
        (order, amountLimit) = getSellOrder(data, data.lastProcessedOrderId);
    }

    function dequeueBuyOrder(Data storage data) external returns (BuyOrder memory order, uint256 amountLimit) {
        ++data.lastProcessedOrderId;
        (order, amountLimit) = 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];
    }
}

File 6 of 16 : 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 addLiquidity(
        address pair,
        uint256 amount0Desired,
        uint256 amount1Desired
    )
        internal
        view
        returns (
            uint256 amount0,
            uint256 amount1,
            uint256 swapToken
        )
    {
        if (amount0Desired == 0 || amount1Desired == 0) {
            if (amount0Desired > 0) {
                swapToken = 1;
            } else if (amount1Desired > 0) {
                swapToken = 2;
            }
            return (0, 0, swapToken);
        }
        (uint256 reserve0, uint256 reserve1) = ITwapPair(pair).getReserves();
        if (reserve0 == 0 && reserve1 == 0) {
            (amount0, amount1) = (amount0Desired, amount1Desired);
        } else {
            require(reserve0 > 0 && reserve1 > 0, 'AL07');
            uint256 amount1Optimal = amount0Desired.mul(reserve1) / reserve0;
            if (amount1Optimal <= amount1Desired) {
                swapToken = 2;
                (amount0, amount1) = (amount0Desired, amount1Optimal);
            } else {
                uint256 amount0Optimal = amount1Desired.mul(reserve0) / reserve1;
                assert(amount0Optimal <= amount0Desired);
                swapToken = 1;
                (amount0, amount1) = (amount0Optimal, amount1Desired);
            }

            uint256 totalSupply = ITwapPair(pair).totalSupply();
            uint256 liquidityOut = Math.min(amount0.mul(totalSupply) / reserve0, amount1.mul(totalSupply) / reserve1);
            if (liquidityOut == 0) {
                amount0 = 0;
                amount1 = 0;
            }
        }
    }

    function addLiquidityAndMint(
        address pair,
        address to,
        address token0,
        address token1,
        uint256 amount0Desired,
        uint256 amount1Desired
    )
        external
        returns (
            uint256 amount0Left,
            uint256 amount1Left,
            uint256 swapToken
        )
    {
        uint256 amount0;
        uint256 amount1;
        (amount0, amount1, swapToken) = addLiquidity(pair, amount0Desired, amount1Desired);
        if (amount0 == 0 || amount1 == 0) {
            return (amount0Desired, amount1Desired, swapToken);
        }
        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,
        uint16 tolerance,
        bytes calldata data
    ) external returns (uint256 amount0Left, uint256 amount1Left) {
        uint256 amount0In = ITwapPair(pair).getDepositAmount0In(amount0, data);
        amount1Left = ITwapPair(pair).getSwapAmount1Out(amount0In, data).sub(tolerance);
        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,
        uint16 tolerance,
        bytes calldata data
    ) external returns (uint256 amount0Left, uint256 amount1Left) {
        uint256 amount1In = ITwapPair(pair).getDepositAmount1In(amount1, data);
        amount0Left = ITwapPair(pair).getSwapAmount0Out(amount1In, data).sub(tolerance);
        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);
    }

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

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

    uint256 private constant PRECISION = 10**18;
    uint256 private constant TOLERANCE = 10**18 + 10**16;

    event UnwrapFailed(address to, uint256 amount);

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

    function sharesToAmount(
        Data storage data,
        address token,
        uint256 share,
        uint256 amountLimit,
        address refundTo
    ) 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);

        if (amountLimit > 0) {
            uint256 amountLimitWithTolerance = amountLimit.mul(TOLERANCE).div(PRECISION);
            if (value > amountLimitWithTolerance) {
                TransferHelper.safeTransfer(token, refundTo, value.sub(amountLimitWithTolerance));
                return amountLimitWithTolerance;
            }
        }

        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 8 of 16 : 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 9 of 16 : 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 10 of 16 : 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 11 of 16 : 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 12 of 16 : 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 13 of 16 : 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 14 of 16 : 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 15 of 16 : 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);

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

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

    function getSwapAmountInMaxOut(
        bool inverse,
        uint256 swapFee,
        uint256 _amountOut,
        bytes calldata data
    ) external view returns (uint256 amountIn, uint256 amountOut);

    function getSwapAmountInMinOut(
        bool inverse,
        uint256 swapFee,
        uint256 _amountOut,
        bytes calldata data
    ) external view returns (uint256 amountIn, uint256 amountOut);
}

File 16 of 16 : 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 }('');
    }
}

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

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":"pair","type":"address"},{"indexed":false,"internalType":"uint16","name":"amount","type":"uint16"}],"name":"ToleranceSet","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"},{"internalType":"uint256","name":"amountLimit","type":"uint256"}],"name":"_executeBuy","outputs":[],"stateMutability":"payable","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"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"name":"_executeDeposit","outputs":[],"stateMutability":"payable","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"},{"internalType":"uint256","name":"amountLimit","type":"uint256"}],"name":"_executeSell","outputs":[],"stateMutability":"payable","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":"payable","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":"payable","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":"payable","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":"payable","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":"payable","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":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_delay","type":"uint32"}],"name":"setDelay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasPriceInertia","type":"uint256"}],"name":"setGasPriceInertia","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxGasLimit","type":"uint256"}],"name":"setMaxGasLimit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxGasPriceImpact","type":"uint256"}],"name":"setMaxGasPriceImpact","outputs":[],"stateMutability":"payable","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":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"},{"internalType":"uint16","name":"amount","type":"uint16"}],"name":"setTolerance","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"gasCost","type":"uint256"}],"name":"setTransferGasCost","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tolerance","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","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"}]

60806040523480156200001157600080fd5b50604051620060c6380380620060c6833981016040819052620000349162000197565b600480546001600160a01b038086166001600160a01b031992831617909255600f80549091163317905581166000908152601060205260409020805460ff19166001179055620f42403a063a03600655600e80546001600160a01b0384166001600160a01b03199091161790556000805463ffffffff1916610708178155624c4b406005556301312d00600755620f424060085560405163b2456a0760e01b8152730edc96c6070fef121cb4a1af50fc8e02fe6a84869163b2456a0791620001069190819061271090600401620001f4565b60006040518083038186803b1580156200011f57600080fd5b505af415801562000134573d6000803e3d6000fd5b505050507f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe233604051620001699190620001e0565b60405180910390a150505062000213565b80516001600160a01b03811681146200019257600080fd5b919050565b600080600060608486031215620001ac578283fd5b620001b7846200017a565b9250620001c7602085016200017a565b9150620001d7604085016200017a565b90509250925092565b6001600160a01b0391909116815260200190565b9283526001600160a01b03919091166020830152604082015260600190565b615ea380620002236000396000f3fe6080604052600436106102975760003560e01c80638da5cb5b1161015a578063c69cee72116100c1578063e5e7988e1161007a578063e5e7988e1461072f578063e6a0cc941461074f578063f16508f614610764578063fe0d94c114610777578063fe136a8e1461078a578063fe173b971461079d5761029e565b8063c69cee72146106a0578063c9cd9760146106b3578063d09ef241146106c6578063d22e9242146106f4578063e30a499314610707578063e5b1be651461071c5761029e565b8063b1af1bda11610113578063b1af1bda14610605578063b32ac93614610625578063ba4d531214610638578063be5813041461064b578063bf6b874e1461066b578063c45a01551461068b5761029e565b80638da5cb5b1461055d57806394531713146105725780639718f627146105855780639d08ebb5146105a5578063a70885c1146105b8578063af482b58146105e55761029e565b80635051349a116101fe578063690910c4116101b7578063690910c4146104cd5780636a42b8f8146104e05780636de3c67c1461050257806377632ec214610517578063793ab297146105375780637f6a1caf1461054a5761029e565b80635051349a14610423578063514fcac71461044357806354df6d7414610463578063576b332b1461049057806357a62a4f146104a35780635e45da23146104b85761029e565b8063390ce0d311610250578063390ce0d3146103545780633bbac579146103815780633ed76f17146103a15780633fc8cef3146103b457806345fa8aae146103d65780634c016016146104035761029e565b806310348665146102a357806313af4035146102b85780631776834a146102cb57806317818a5c146102de57806320a68fab14610314578063342aa8b5146103415761029e565b3661029e57005b600080fd5b6102b66102b13660046153bd565b6107b2565b005b6102b66102c6366004614e25565b610835565b6102b66102d936600461533d565b6108d0565b3480156102ea57600080fd5b506102fe6102f936600461533d565b610967565b60405161030b9190615ca7565b60405180910390f35b34801561032057600080fd5b5061033461032f366004614e25565b610a02565b60405161030b91906157c1565b6102b661034f366004614f5e565b610a0e565b34801561036057600080fd5b5061037461036f36600461533d565b610a9a565b60405161030b91906159fb565b34801561038d57600080fd5b5061033461039c366004614e25565b610b34565b6102b66103af366004614e9d565b610b49565b3480156103c057600080fd5b506103c9610b69565b60405161030b9190615634565b3480156103e257600080fd5b506103f66103f136600461533d565b610b78565b60405161030b9190615822565b34801561040f57600080fd5b5061033461041e366004614e25565b610b84565b6104366104313660046150f5565b610b90565b60405161030b9190615a27565b34801561044f57600080fd5b506102b661045e36600461533d565b610c33565b34801561046f57600080fd5b5061048361047e36600461533d565b610d1c565b60405161030b9190615c76565b61043661049e366004615259565b610db8565b3480156104af57600080fd5b50610436610e1b565b3480156104c457600080fd5b50610436610e21565b6102b66104db366004615259565b610e27565b3480156104ec57600080fd5b506104f5611188565b60405161030b9190615db7565b34801561050e57600080fd5b50610436611194565b34801561052357600080fd5b5061033461053236600461533d565b61119a565b6102b6610545366004614fe3565b6111af565b6102b6610558366004614f96565b611257565b34801561056957600080fd5b506103c96112eb565b6102b661058036600461533d565b6112fa565b34801561059157600080fd5b506104366105a0366004614e25565b61135e565b6104366105b336600461523d565b611379565b3480156105c457600080fd5b506105d86105d3366004614e25565b6113df565b60405161030b9190615d26565b3480156105f157600080fd5b50610334610600366004614e25565b6113f5565b34801561061157600080fd5b5061037461062036600461533d565b611401565b6102b661063336600461533d565b611443565b6104366106463660046150f5565b6114a7565b34801561065757600080fd5b506102b661066636600461533d565b61150d565b34801561067757600080fd5b50610436610686366004614e25565b611556565b34801561069757600080fd5b506103c9611571565b6102b66106ae36600461509b565b611580565b6102b66106c1366004614e5d565b611c66565b3480156106d257600080fd5b506106e66106e136600461533d565b611c95565b60405161030b929190615836565b6102b6610702366004615016565b611cab565b34801561071357600080fd5b50610436611d3d565b6102b661072a366004614f0c565b611d43565b34801561073b57600080fd5b5061033461074a366004614e25565b611f42565b34801561075b57600080fd5b50610436611f4e565b6102b6610772366004615111565b611f54565b6102b661078536600461533d565b6122f5565b6102b661079836600461509b565b61254c565b3480156107a957600080fd5b5061043661279f565b600f546001600160a01b031633146107e55760405162461bcd60e51b81526004016107dc906158ed565b60405180910390fd5b6000805463ffffffff191663ffffffff83161790556040517f63e09f16584208fba1fc7ff64c62b00f07bec177c0d97ca6689891b1e77a35c79061082a908390615db7565b60405180910390a150565b600f546001600160a01b0316331461085f5760405162461bcd60e51b81526004016107dc906158ed565b6001600160a01b0381166108855760405162461bcd60e51b81526004016107dc90615983565b600f80546001600160a01b0319166001600160a01b0383161790556040517f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe29061082a908390615634565b600f546001600160a01b031633146108fa5760405162461bcd60e51b81526004016107dc906158ed565b604051636702eca360e01b8152730edc96c6070fef121cb4a1af50fc8e02fe6a848690636702eca390610934906000908590600401615c3c565b60006040518083038186803b15801561094c57600080fd5b505af4158015610960573d6000803e3d6000fd5b5050505050565b61096f614b70565b604051634ce4436960e11b8152730edc96c6070fef121cb4a1af50fc8e02fe6a8486906399c886d2906109a9906000908690600401615c3c565b6101206040518083038186803b1580156109c257600080fd5b505af41580156109d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109fa9190615275565b90505b919050565b60006109fa81836127a5565b600f546001600160a01b03163314610a385760405162461bcd60e51b81526004016107dc906158ed565b6001600160a01b03821660009081526010602052604090819020805460ff1916831515179055517f70af441dbb427737e6a5ef2cf5b664321011765ce1d19ce4a69cd024e69d4f2f90610a8e9084908490615789565b60405180910390a15050565b610aa2614bd3565b60405163ac1ecdb360e01b8152730edc96c6070fef121cb4a1af50fc8e02fe6a84869063ac1ecdb390610adc906000908690600401615c3c565b6101806040518083038186803b158015610af557600080fd5b505af4158015610b09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2d91906150c7565b5092915050565b60106020526000908152604090205460ff1681565b610b5585878684611d43565b610b6183878484611d43565b505050505050565b600e546001600160a01b031690565b60006109fa81836127da565b60006109fa818361287c565b6000601254600014610bb45760405162461bcd60e51b81526004016107dc90615857565b600160125560405162c44ff160e31b8152730edc96c6070fef121cb4a1af50fc8e02fe6a8486906306227f8890610bf5906000908690600d90600401615a83565b60006040518083038186803b158015610c0d57600080fd5b505af4158015610c21573d6000803e3d6000fd5b50506001546000601255949350505050565b60125415610c535760405162461bcd60e51b81526004016107dc90615857565b60016012556002610c656000836127da565b6005811115610c7057fe5b14610c8d5760405162461bcd60e51b81526004016107dc90615965565b600080610c9a8184612885565b60005491935063ffffffff90811692504291610cca916201518091610cc49186918116906128ba16565b906128ea565b10610ce75760405162461bcd60e51b81526004016107dc90615875565b6000838152600b60205260409020805460ff19166001908117909155610d129083908390869061292b565b5050600060125550565b610d24614c2f565b60405163117d7ab160e01b8152730edc96c6070fef121cb4a1af50fc8e02fe6a84869063117d7ab190610d5e906000908690600401615c3c565b6101e06040518083038186803b158015610d7757600080fd5b505af4158015610d8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610daf919061514c565b50909392505050565b6000601254600014610ddc5760405162461bcd60e51b81526004016107dc90615857565b6001601255604051636587992160e01b8152730edc96c6070fef121cb4a1af50fc8e02fe6a848690636587992190610bf5906000908690600401615b91565b60085490565b60055490565b333014610e465760405162461bcd60e51b81526004016107dc906158ed565b426202a300610e5d610120840161010085016153bd565b63ffffffff16011015610e825760405162461bcd60e51b81526004016107dc90615947565b60008080610e9e610e9660208601866153bd565b600090612ed7565b925092509250826001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610edf57600080fd5b505af1158015610ef3573d6000803e3d6000fd5b50505050610f0683848660200135612f10565b60008080610f1a60a0880160808901615041565b8015610f4a5750600e546001600160a01b0386811691161480610f4a5750600e546001600160a01b038581169116145b156110b957600073c1963430691708bee5d24b4e7d66ca8c9191a20863cf58beed87878a600d60010160009054906101000a90046001600160a01b03168d60a0016020810190610f9a9190614e25565b60008052600a602052600080516020615e4e833981519152546040516001600160e01b031960e089901b168152610fd996959493929190600401615661565b60806040518083038186803b158015610ff157600080fd5b505af4158015611005573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611029919061505d565b919650945092509050806110b35773c7903ce6cfae211a0cbbcf1a8d721ee71a29746663656621e0600d61106360c08c0160a08d01614e25565b876040518463ffffffff1660e01b815260040161108293929190615a64565b60006040518083038186803b15801561109a57600080fd5b505af41580156110ae573d6000803e3d6000fd5b505050505b5061114b565b6001600160a01b0386166389afcb446110d860c08a0160a08b01614e25565b6040518263ffffffff1660e01b81526004016110f49190615634565b6040805180830381600087803b15801561110d57600080fd5b505af1158015611121573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611145919061536d565b90925090505b86604001358210158015611163575086606001358110155b61117f5760405162461bcd60e51b81526004016107dc906158b1565b50505050505050565b60005463ffffffff1690565b60075490565b6000908152600b602052604090205460ff1690565b600f546001600160a01b031633146111d95760405162461bcd60e51b81526004016107dc906158ed565b600a61ffff821611156111fe5760405162461bcd60e51b81526004016107dc90615929565b6001600160a01b03821660009081526011602052604090819020805461ffff191661ffff8416179055517f6b4044e33be5af8fcdb7449c49137010eede3c8c06d5d08067151a7ace17266d90610a8e90849084906157a4565b600f546001600160a01b031633146112815760405162461bcd60e51b81526004016107dc906158ed565b60405163146bce4f60e31b8152730edc96c6070fef121cb4a1af50fc8e02fe6a84869063a35e7278906112bf90600090879087908790600401615a30565b60006040518083038186803b1580156112d757600080fd5b505af415801561117f573d6000803e3d6000fd5b600f546001600160a01b031681565b600f546001600160a01b031633146113245760405162461bcd60e51b81526004016107dc906158ed565b604051630fd1437d60e11b8152730edc96c6070fef121cb4a1af50fc8e02fe6a848690631fa286fa90610934906000908590600401615c3c565b6001600160a01b03166000908152600a602052604090205490565b600060125460001461139d5760405162461bcd60e51b81526004016107dc90615857565b6001601255604051638f0e6bef60e01b8152730edc96c6070fef121cb4a1af50fc8e02fe6a848690638f0e6bef90610bf5906000908690600d90600401615aa7565b60116020526000908152604090205461ffff1681565b60006109fa818361305b565b611409614bd3565b6040516311c8197f60e01b8152730edc96c6070fef121cb4a1af50fc8e02fe6a8486906311c8197f90610adc906000908690600401615c3c565b600f546001600160a01b0316331461146d5760405162461bcd60e51b81526004016107dc906158ed565b60405163153cc2fd60e31b8152730edc96c6070fef121cb4a1af50fc8e02fe6a84869063a9e617e890610934906000908590600401615c3c565b60006012546000146114cb5760405162461bcd60e51b81526004016107dc90615857565b600160125560405163758e99b360e01b8152730edc96c6070fef121cb4a1af50fc8e02fe6a84869063758e99b390610bf5906000908690600d90600401615a83565b6012541561152d5760405162461bcd60e51b81526004016107dc90615857565b600160125560008061153f8184613064565b63ffffffff1691509150610d12828285600061292b565b6001600160a01b03166000908152600d602052604090205490565b6004546001600160a01b031690565b33301461159f5760405162461bcd60e51b81526004016107dc906158ed565b426202a3006115b6610120850161010086016153bd565b63ffffffff160110156115db5760405162461bcd60e51b81526004016107dc90615947565b600080806116046115ef60208701876153bd565b6115ff6040880160208901615041565b6130a2565b91945092509050600073c7903ce6cfae211a0cbbcf1a8d721ee71a29746663a8d669b4600d8560408a01358961164060c08d0160a08e01614e25565b6040518663ffffffff1660e01b8152600401611660959493929190615c4a565b60206040518083038186803b15801561167857600080fd5b505af415801561168c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b09190615355565b9050836001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156116ed57600080fd5b505af1158015611701573d6000803e3d6000fd5b50505050600061172a858861012001358961014001602081019061172591906153bd565b6130de565b90506000806000806000896001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401604080518083038186803b15801561176c57600080fd5b505afa158015611780573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a4919061530b565b915091506117db60018d60200160208101906117c09190615041565b6117ca57826117cc565b835b6001600160701b0316906128ba565b925050506000886001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561181a57600080fd5b505afa15801561182e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118529190614e41565b90506000896001600160a01b03166354cf2aeb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561188f57600080fd5b505afa1580156118a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c79190615355565b9050816001600160a01b031663daab4b6e8d60200160208101906118eb9190615041565b838f606001358a6040518563ffffffff1660e01b815260040161191194939291906157cc565b604080518083038186803b15801561192857600080fd5b505afa15801561193c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611960919061536d565b9095509350600083851115611a265761198760608e01356119818a876131fc565b90613251565b9050826001600160a01b031663a7d208778e60200160208101906119ab9190615041565b84878b6040518563ffffffff1660e01b81526004016119cd94939291906157cc565b604080518083038186803b1580156119e457600080fd5b505afa1580156119f8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1c919061536d565b9096509450611a30565b5060608c01359350865b85811015611a505760405162461bcd60e51b81526004016107dc906159a1565b85881115611ad557600e546001600160a01b038b81169116148015611a805750611a8060a08e0160808f01615041565b15611aaf57611aaa8d60a0016020810190611a9b9190614e25565b611aa58a896128ba565b613281565b611ad5565b611ad58a8e60a0016020810190611ac69190614e25565b611ad08b8a6128ba565b612f10565b611ae08a8c88612f10565b5050506001600160a01b038816600090815260116020526040902054611b0b90839061ffff166128ba565b9150600080611b2060408d0160208e01615041565b15611b2d57839150611b30565b50825b600e546001600160a01b038981169116148015611b585750611b5860a08d0160808e01615041565b15611be15760405163022c0d9f60e01b81526001600160a01b038b169063022c0d9f90611b8f908590859030908c90600401615d4e565b600060405180830381600087803b158015611ba957600080fd5b505af1158015611bbd573d6000803e3d6000fd5b50611bdc9250611bd691505060c08e0160a08f01614e25565b85613281565b611c58565b896001600160a01b031663022c0d9f83838f60a0016020810190611c059190614e25565b8a6040518563ffffffff1660e01b8152600401611c259493929190615d4e565b600060405180830381600087803b158015611c3f57600080fd5b505af1158015611c53573d6000803e3d6000fd5b505050505b505050505050505050505050565b333014611c855760405162461bcd60e51b81526004016107dc906158ed565b611c90838383612f10565b505050565b600080611ca28184612885565b91509150915091565b600f546001600160a01b03163314611cd55760405162461bcd60e51b81526004016107dc906158ed565b60405163b2456a0760e01b8152730edc96c6070fef121cb4a1af50fc8e02fe6a84869063b2456a0790611d119060009086908690600401615a64565b60006040518083038186803b158015611d2957600080fd5b505af4158015610b61573d6000803e3d6000fd5b60015490565b333014611d625760405162461bcd60e51b81526004016107dc906158ed565b600e546001600160a01b038581169116148015611d7c5750805b15611ea357604051632a359a6d60e21b815260009073c7903ce6cfae211a0cbbcf1a8d721ee71a2974669063a8d669b490611dc490600d908990889087908b90600401615c4a565b60206040518083038186803b158015611ddc57600080fd5b505af4158015611df0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e149190615355565b600e54604051632e1a7d4d60e01b81529192506001600160a01b031690632e1a7d4d90611e45908490600401615a27565b600060405180830381600087803b158015611e5f57600080fd5b505af1158015611e73573d6000803e3d6000fd5b5050600080525050600a602052600080516020615e4e83398151915254611e9d90859083906133a1565b50611f3c565b604051632a359a6d60e21b8152611f3c908590859073c7903ce6cfae211a0cbbcf1a8d721ee71a2974669063a8d669b490611eec90600d9086908a906000908890600401615c4a565b60206040518083038186803b158015611f0457600080fd5b505af4158015611f18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad09190615355565b50505050565b60006109fa8183613433565b60025490565b333014611f735760405162461bcd60e51b81526004016107dc906158ed565b426202a300611f8a610160860161014087016153bd565b63ffffffff16011015611faf5760405162461bcd60e51b81526004016107dc90615947565b600080600080611fc087878761343c565b92965090945092509050611fda60e0880160c08901615041565b8015611fe557508015155b1561220a57835160009061200b906101608a01356117256101a08c016101808d016153bd565b9050831580159061201c5750816001145b1561210d57600073a1f563cc7da98a87983aec5d5d3dfdb53ef4c97463d0b0a9bc87600001518860200151888d60600135601160008d600001516001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a900461ffff16886040518763ffffffff1660e01b81526004016120a796959493929190615739565b604080518083038186803b1580156120be57600080fd5b505af41580156120d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120f6919061536d565b909550905061210584826128ea565b935050612208565b821580159061211c5750816002145b1561220857600073a1f563cc7da98a87983aec5d5d3dfdb53ef4c97463adf5f8f387600001518860400151878d60800135601160008d600001516001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a900461ffff16886040518763ffffffff1660e01b81526004016121a796959493929190615739565b604080518083038186803b1580156121be57600080fd5b505af41580156121d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f6919061536d565b9450905061220485826128ea565b9450505b505b821580159061221857508115155b156122d057835173a1f563cc7da98a87983aec5d5d3dfdb53ef4c97490637a528bd29061224c6101008b0160e08c01614e25565b8760200151886040015188886040518763ffffffff1660e01b81526004016122799695949392919061569c565b60606040518083038186803b15801561229157600080fd5b505af41580156122a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c99190615390565b5090935091505b61117f6122e4610100890160e08a01614e25565b856020015186604001518686613780565b601254156123155760405162461bcd60e51b81526004016107dc90615857565b60016012556040517f892cd8f5b436bd5fb7dac1f11aafb73345d892ba3e9fe09cd94d95ba84928e739061234c9033908490615648565b60405180910390a160005a3360009081526010602052604081205491925090819060ff16806123a557506000805260106020527f6e0956cda88cad152e89927e53611735b61a5c762d1428573c6931b0a5efcb015460ff165b905060005b848110156124c5576002546001016000908152600b602052604090205460ff16156123de576123d960006137a2565b6124bd565b6000806123eb60006137ae565b909250905060008260048111156123fe57fe5b148061240a5750428110155b156124165750506124c5565b838061242657506104b081014210155b6124425760405162461bcd60e51b81526004016107dc906158ed565b600194508482600481111561245357fe5b1415612466576124616137d2565b6124ba565b600282600481111561247457fe5b141561248257612461613a22565b600382600481111561249057fe5b141561249e57612461613c26565b60048260048111156124ac57fe5b14156124ba576124ba613e84565b50505b6001016123aa565b50811561254157730edc96c6070fef121cb4a1af50fc8e02fe6a8486639db74df160006124f35a87906128ba565b6040518363ffffffff1660e01b8152600401612510929190615c3c565b60006040518083038186803b15801561252857600080fd5b505af415801561253c573d6000803e3d6000fd5b505050505b505060006012555050565b33301461256b5760405162461bcd60e51b81526004016107dc906158ed565b426202a300612582610120850161010086016153bd565b63ffffffff160110156125a75760405162461bcd60e51b81526004016107dc90615947565b600080806125bb6115ef60208701876153bd565b925092509250826001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156125fc57600080fd5b505af1158015612610573d6000803e3d6000fd5b505050506000612634848761012001358861014001602081019061172591906153bd565b905060006126458787878786613f80565b905060008061265a60408a0160208b01615041565b6126665760008361266a565b8260005b600e5491935091506001600160a01b038681169116148015612697575061269760a08a0160808b01615041565b156127205760405163022c0d9f60e01b81526001600160a01b0388169063022c0d9f906126ce908590859030908a90600401615d4e565b600060405180830381600087803b1580156126e857600080fd5b505af11580156126fc573d6000803e3d6000fd5b5061271b925061271591505060c08b0160a08c01614e25565b84613281565b612794565b6001600160a01b03871663022c0d9f838361274160c08e0160a08f01614e25565b886040518563ffffffff1660e01b81526004016127619493929190615d4e565b600060405180830381600087803b15801561277b57600080fd5b505af115801561278f573d6000803e3d6000fd5b505050505b505050505050505050565b60065490565b600060025b6001600160a01b0383166000908152600c85016020526040902054600160ff9283161b1616151590505b92915050565b600082600101548211156127f0575060006127d4565b6000828152600b8401602052604090205460ff1615612811575060056127d4565b61281b8383614467565b15612828575060046127d4565b6000806128358585612885565b9092509050600082600481111561284857fe5b1415612859576003925050506127d4565b428163ffffffff1610612871576001925050506127d4565b506002949350505050565b600060036127aa565b60008181526003830160205260408120805463ffffffff61010082041691906128b09060ff1661449e565b9250509250929050565b60006128e383836040518060400160405280600481526020016329a6989960e11b81525061450e565b9392505050565b808201828110156127d4576040805162461bcd60e51b81526020600480830191909152602482015263534d344560e01b604482015290519081900360640190fd5b600084600481111561293957fe5b14156129575760405162461bcd60e51b81526004016107dc906159bf565b600042612968856301e133806128ea565b109050600185600481111561297957fe5b1415612ad75760405163117d7ab160e01b8152600090730edc96c6070fef121cb4a1af50fc8e02fe6a84869063117d7ab1906129bb9084908890600401615c3c565b6101e06040518083038186803b1580156129d457600080fd5b505af41580156129e8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a0c919061514c565b50509050600080612a2b83600001516000612ed790919063ffffffff16565b9250925050600084612a41578360e00151612a4e565b600f546001600160a01b03165b9050612a6a818486602001518588604001518960a001516145a6565b612a865760405162461bcd60e51b81526004016107dc90615893565b8515612ace57612ab281612aad8661012001518761010001516131fc90919063ffffffff16565b614730565b612ace5760405162461bcd60e51b81526004016107dc9061590b565b50505050612ecc565b6002856004811115612ae557fe5b1415612c2b57604051634ce4436960e11b8152600090730edc96c6070fef121cb4a1af50fc8e02fe6a8486906399c886d290612b279084908890600401615c3c565b6101206040518083038186803b158015612b4057600080fd5b505af4158015612b54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b789190615275565b8051909150600090612b8b908290612ed7565b50509050600083612ba0578260a00151612bad565b600f546001600160a01b03165b9050612bc68282856020015163c9cd976060e01b6147b1565b612be25760405162461bcd60e51b81526004016107dc90615893565b8415612c2357612c0781612aad8560e001518660c001516131fc90919063ffffffff16565b612c235760405162461bcd60e51b81526004016107dc9061590b565b505050612ecc565b6003856004811115612c3957fe5b1415612d745760405163ac1ecdb360e01b8152600090730edc96c6070fef121cb4a1af50fc8e02fe6a84869063ac1ecdb390612c7b9084908890600401615c3c565b6101806040518083038186803b158015612c9457600080fd5b505af4158015612ca8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ccc91906150c7565b509050600080612cea83600001516000612ed790919063ffffffff16565b9250925050600084612d00578360a00151612d0d565b600f546001600160a01b03165b9050612d338460200151612d215783612d23565b825b82866040015187608001516148cc565b612d4f5760405162461bcd60e51b81526004016107dc90615893565b8515612ace57612ab281612aad8660e001518760c001516131fc90919063ffffffff16565b6004856004811115612d8257fe5b1415612ecc576040516311c8197f60e01b8152600090730edc96c6070fef121cb4a1af50fc8e02fe6a8486906311c8197f90612dc49084908890600401615c3c565b6101806040518083038186803b158015612ddd57600080fd5b505af4158015612df1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e1591906150c7565b509050600080612e3383600001516000612ed790919063ffffffff16565b9250925050600084612e49578360a00151612e56565b600f546001600160a01b03165b9050612e6a8460200151612d215783612d23565b612e865760405162461bcd60e51b81526004016107dc90615893565b8515612ec757612eab81612aad8660e001518760c001516131fc90919063ffffffff16565b612ec75760405162461bcd60e51b81526004016107dc9061590b565b505050505b610960600084614918565b63ffffffff166000908152600990910160205260409020805460018201546002909201546001600160a01b039182169392821692911690565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b60208310612f8c5780518252601f199092019160209182019101612f6d565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612fee576040519150601f19603f3d011682016040523d82523d6000602084013e612ff3565b606091505b5091509150818015613021575080511580613021575080806020019051602081101561301e57600080fd5b50515b610960576040805162461bcd60e51b815260206004808301919091526024820152635448303560e01b604482015290519081900360640190fd5b600060016127aa565b6000806130718484614467565b61308d5760405162461bcd60e51b81526004016107dc906159dd565b6130978484612885565b909590945092505050565b600080808080806130b38189612ed7565b925092509250600080886130c85783836130cb565b82845b9598509650939450505050509250925092565b60606000846001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561311b57600080fd5b505afa15801561312f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131539190614e41565b6001600160a01b0316638c09166e85856040518363ffffffff1660e01b8152600401613180929190615da3565b60206040518083038186803b15801561319857600080fd5b505afa1580156131ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131d09190615355565b9050806040516020016131e39190615a27565b6040516020818303038152906040529150509392505050565b60008115806132175750508082028282828161321457fe5b04145b6127d4576040805162461bcd60e51b81526020600480830191909152602482015263534d324160e01b604482015290519081900360640190fd5b600061325d838361495c565b905061326982826131fc565b83146127d45761327a8160016128ea565b90506127d4565b600e54604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906132b1908490600401615a27565b600060405180830381600087803b1580156132cb57600080fd5b505af11580156132df573d6000803e3d6000fd5b50506000808052600a602052600080516020615e4e833981519152546040519193506001600160a01b038616925090849061331990615631565b600060405180830381858888f193505050503d8060008114613357576040519150601f19603f3d011682016040523d82523d6000602084013e61335c565b606091505b5050905080611c905760405163032b310f60e51b815273c7903ce6cfae211a0cbbcf1a8d721ee71a2974669063656621e0906112bf90600d9087908790600401615a64565b6040516000906001600160a01b038516908390859084818181858888f193505050503d80600081146133ef576040519150601f19603f3d011682016040523d82523d6000602084013e6133f4565b606091505b5050905080611f3c576040805162461bcd60e51b815260206004808301919091526024820152632a2419a360e11b604482015290519081900360640190fd5b600060046127aa565b613444614cb6565b6000808060098161345860208a018a6153bd565b63ffffffff1663ffffffff1681526020019081526020016000206040518060600160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016002820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152505093506000600d73c7903ce6cfae211a0cbbcf1a8d721ee71a29746663a8d669b4909187602001518b602001358b8d60e001602081019061354a9190614e25565b6040518663ffffffff1660e01b815260040161356a959493929190615c4a565b60206040518083038186803b15801561358257600080fd5b505af4158015613596573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ba9190615355565b90506000600d73c7903ce6cfae211a0cbbcf1a8d721ee71a29746663a8d669b4909188604001518c604001358b8e60e00160208101906135fa9190614e25565b6040518663ffffffff1660e01b815260040161361a959493929190615c4a565b60206040518083038186803b15801561363257600080fd5b505af4158015613646573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061366a9190615355565b905085600001516001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156136ab57600080fd5b505af11580156136bf573d6000803e3d6000fd5b5050875173a1f563cc7da98a87983aec5d5d3dfdb53ef4c9749250637a528bd291506136f26101008d0160e08e01614e25565b89602001518a6040015187876040518763ffffffff1660e01b815260040161371f9695949392919061569c565b60606040518083038186803b15801561373757600080fd5b505af415801561374b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061376f9190615390565b979b919a5098509596505050505050565b811561379157613791848684612f10565b801561096057610960838683612f10565b60020180546001019055565b6000806137c2838460020154600101612885565b90925063ffffffff169050915091565b60005a9050600080600080730edc96c6070fef121cb4a1af50fc8e02fe6a848663a81df10f90916040518263ffffffff1660e01b81526004016138159190615a27565b6101e06040518083038186803b15801561382e57600080fd5b505af4158015613842573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613866919061514c565b92509250925060008061388785600001516000612ed790919063ffffffff16565b6001600160a01b038082166000908152600a6020526040808220549285168252812054939650919450909250829130916138da916138ce9190610cc49062012c6c906128ea565b6101208a0151906128ba565b6040516378b2847b60e11b906138f8908b908b908b90602401615c85565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516139369190615615565b60006040518083038160008787f1925050503d8060008114613974576040519150601f19603f3d011682016040523d82523d6000602084013e613979565b606091505b5090925090506001826139a7576139a48860e00151868a60200151878c604001518d60a001516145a6565b90505b6139b0816149ac565b6000806139cd8a61012001518b61010001518d8d60e001516149cd565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613a0d939291906157fd565b60405180910390a35050505050505050505050565b60005a6040516313ed2f6160e01b8152909150600090730edc96c6070fef121cb4a1af50fc8e02fe6a8486906313ed2f6190613a62908490600401615a27565b6101206040518083038186803b158015613a7b57600080fd5b505af4158015613a8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ab39190615275565b905060008030613ad6613acb62012c6c61d6d86128ea565b60e0860151906128ba565b604051631a42443160e21b90613af0908790602401615ca7565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613b2e9190615615565b60006040518083038160008787f1925050503d8060008114613b6c576040519150601f19603f3d011682016040523d82523d6000602084013e613b71565b606091505b509092509050600182613bb1578351600090613b8e908290612ed7565b50509050613bad818660a00151876020015163c9cd976060e01b6147b1565b9150505b613bba816149ac565b600080613bd58660e001518760c00151898960a001516149cd565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613c15939291906157fd565b60405180910390a350505050505050565b60005a604051632e9d30e160e01b81529091506000908190730edc96c6070fef121cb4a1af50fc8e02fe6a848690632e9d30e190613c68908490600401615a27565b6101806040518083038186803b158015613c8157600080fd5b505af4158015613c95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cb991906150c7565b91509150600080613cd884600001516000612ed790919063ffffffff16565b9250925050600080306001600160a01b0316613d37613d2c6000600a0160008a60200151613d065788613d08565b875b6001600160a01b0316815260208101919091526040016000205462012c6c906128ea565b60e0890151906128ba565b604051637f09b54760e11b90613d53908a908a90602401615a0a565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613d919190615615565b60006040518083038160008787f1925050503d8060008114613dcf576040519150601f19603f3d011682016040523d82523d6000602084013e613dd4565b606091505b509092509050600182613e0c57613e098760200151613df35785613df5565b845b8860a0015189604001518a608001516148cc565b90505b613e15816149ac565b600080613e308960e001518a60c001518c8c60a001516149cd565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613e70939291906157fd565b60405180910390a350505050505050505050565b60005a60405163a1ba139560e01b81529091506000908190730edc96c6070fef121cb4a1af50fc8e02fe6a84869063a1ba139590613ec6908490600401615a27565b6101806040518083038186803b158015613edf57600080fd5b505af4158015613ef3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f1791906150c7565b91509150600080613f3684600001516000612ed790919063ffffffff16565b9250925050600080306001600160a01b0316613f64613d2c6000600a0160008a60200151613d065788613d08565b60405163634e773960e11b90613d53908a908a90602401615a0a565b600080600080866001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401604080518083038186803b158015613fbe57600080fd5b505afa158015613fd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ff6919061530b565b909250905061401060016117c060408c0160208d01615041565b925050506000856001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561404f57600080fd5b505afa158015614063573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140879190614e41565b90506000866001600160a01b03166354cf2aeb6040518163ffffffff1660e01b815260040160206040518083038186803b1580156140c457600080fd5b505afa1580156140d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140fc9190615355565b90506000600d73c7903ce6cfae211a0cbbcf1a8d721ee71a29746663a8d669b49091898d604001358d8f60a00160208101906141389190614e25565b6040518663ffffffff1660e01b8152600401614158959493929190615c4a565b60206040518083038186803b15801561417057600080fd5b505af4158015614184573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141a89190615355565b90506141ba60408b0160208c01615041565b614243576040516304a8fad760e31b81526001600160a01b03841690632547d6b8906141ee90859085908b90600401615d7b565b60206040518083038186803b15801561420657600080fd5b505afa15801561421a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061423e9190615355565b6142c3565b60405163c4109d2560e01b81526001600160a01b0384169063c4109d259061427390859085908b90600401615d7b565b60206040518083038186803b15801561428b57600080fd5b505afa15801561429f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142c39190615355565b94506000848611156143fd576142e7866142e160608e0135886131fc565b9061495c565b90506000829050846001600160a01b031663a7d208778d60200160208101906143109190615041565b86898c6040518563ffffffff1660e01b815260040161433294939291906157cc565b604080518083038186803b15801561434957600080fd5b505afa15801561435d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614381919061536d565b600e549098509093506001600160a01b038a811691161480156143af57506143af60a08d0160808e01615041565b156143d6576143d16143c760c08e0160a08f01614e25565b611aa583866128ba565b6143f7565b6143f7898d60a00160208101906143ed9190614e25565b611ad084876128ba565b50614404565b5060608a01355b6001600160a01b03891660009081526011602052604090205461442c90879061ffff166128ba565b95508086101561444e5760405162461bcd60e51b81526004016107dc906158cf565b614459888a84612f10565b505050505095945050505050565b600081815260038301602052604081205465010000000000900460ff166002811480614496575060ff81166003145b949350505050565b600060018214156144b1575060016109fd565b60028214156144c2575060026109fd565b60038214156144d3575060046109fd565b60048214156144e4575060046109fd565b60058214156144f5575060036109fd565b6006821415614506575060036109fd565b506000919050565b818303818482111561459e5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561456357818101518382015260200161454b565b50505050905090810190601f1680156145905780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509392505050565b6001600160a01b038381166000908152600a602052604080822054928816825281205490918291829130916145da916128ea565b604051633ed76f1760e01b906145fe908d908d908d908d908d908d906024016156d6565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161463c9190615615565b60006040518083038160008787f1925050503d806000811461467a576040519150601f19603f3d011682016040523d82523d6000602084013e61467f565b606091505b50915091508161472457876001600160a01b0316896001600160a01b03167f786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b21159289846040516146ce929190615d35565b60405180910390a3856001600160a01b0316896001600160a01b03167f786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b211592878460405161471b929190615d35565b60405180910390a35b50979650505050505050565b60008161473f575060016127d4565b60008052600a602052600080516020615e4e833981519152546147659084908490614a5d565b9050801515836001600160a01b03167fdbef2fc26e7694e7a1c5a4801b1ad144136d149cf76f310a780689b4087f0ffe846040516147a39190615a27565b60405180910390a392915050565b6000826147c057506001614496565b600080306001600160a01b031661d6d88589898960006040516024016147e99493929190615710565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516148279190615615565b60006040518083038160008787f1925050503d8060008114614865576040519150601f19603f3d011682016040523d82523d6000602084013e61486a565b606091505b5091509150816148c257866001600160a01b0316866001600160a01b03167f786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b21159287846040516148b9929190615d35565b60405180910390a35b5095945050505050565b6000826148db57506001614496565b6001600160a01b0385166000908152600a60205260408082205490518291309163e5b1be6560e01b906147e9908b908b908b908b90602401615710565b6000908152600391820160205260408120818155600181018290556002810180546001600160e81b03191690559182015560040180546001600160e01b0319169055565b600080821161499b576040805162461bcd60e51b81526020600480830191909152602482015263534d343360e01b604482015290519081900360640190fd5b8183816149a457fe5b049392505050565b806149c0576149bb6000614abb565b6149ca565b6149ca6000614b0e565b50565b600080806149db87876131fc565b90506149ee615594610cc45a88906128ba565b92506000614a1382614a0e600060060154876131fc90919063ffffffff16565b614b5a565b9050614a1f82826128ba565b9250614a2b3382614730565b614a475760405162461bcd60e51b81526004016107dc9061590b565b614a518584614730565b50505094509492505050565b6040516000906001600160a01b038516908390859084818181858888f193505050503d8060008114614aab576040519150601f19603f3d011682016040523d82523d6000602084013e614ab0565b606091505b509095945050505050565b600281015460009081526003820160205260409020805465010000000000900460ff1615614aea576003614aed565b60025b815460ff91909116650100000000000265ff00000000001990911617905550565b60028082015460009081526003928301602052604081208181556001810182905591820180546001600160e81b03191690559181019190915560040180546001600160e01b0319169055565b6000818310614b6957816128e3565b5090919050565b604051806101200160405280600063ffffffff16815260200160008152602001600081526020016000815260200160001515815260200160006001600160a01b031681526020016000815260200160008152602001600063ffffffff1681525090565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b604051806101a00160405280600063ffffffff1681526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160006001600160a01b031681526020016000815260200160008152602001600063ffffffff16815260200160008152602001600063ffffffff1681525090565b604080516060810182526000808252602082018190529181019190915290565b80356109fd81615e18565b80516109fd81615e18565b80356109fd81615e2d565b80516109fd81615e2d565b60006101608284031215614d14578081fd5b50919050565b6000610160808385031215614d2d578182fd5b614d3681615dc8565b915050614d4282614e1a565b8152614d5060208301614cf7565b60208201526040820151604082015260608201516060820152614d7560808301614cf7565b6080820152614d8660a08301614ce1565b60a082015260c082015160c082015260e082015160e0820152610100614dad818401614e1a565b908201526101208281015190820152610140614dca818401614e1a565b9082015292915050565b60006101008284031215614d14578081fd5b60006101208284031215614d14578081fd5b80516001600160701b03811681146109fd57600080fd5b80356109fd81615e3b565b80516109fd81615e3b565b600060208284031215614e36578081fd5b81356128e381615e18565b600060208284031215614e52578081fd5b81516128e381615e18565b600080600060608486031215614e71578182fd5b8335614e7c81615e18565b92506020840135614e8c81615e18565b929592945050506040919091013590565b60008060008060008060c08789031215614eb5578384fd5b8635614ec081615e18565b95506020870135614ed081615e18565b9450604087013593506060870135614ee781615e18565b92506080870135915060a0870135614efe81615e2d565b809150509295509295509295565b60008060008060808587031215614f21578182fd5b8435614f2c81615e18565b93506020850135614f3c81615e18565b9250604085013591506060850135614f5381615e2d565b939692955090935050565b60008060408385031215614f70578182fd5b8235614f7b81615e18565b91506020830135614f8b81615e2d565b809150509250929050565b600080600060608486031215614faa578081fd5b8335614fb581615e18565b9250602084013560058110614fc8578182fd5b91506040840135614fd881615e2d565b809150509250925092565b60008060408385031215614ff5578182fd5b823561500081615e18565b9150602083013561ffff81168114614f8b578182fd5b60008060408385031215615028578182fd5b823561503381615e18565b946020939093013593505050565b600060208284031215615052578081fd5b81356128e381615e2d565b60008060008060808587031215615072578182fd5b845161507d81615e2d565b60208601516040870151606090970151919890975090945092505050565b60008061018083850312156150ae578182fd5b6150b88484614d02565b94610160939093013593505050565b60008061018083850312156150da578182fd5b6150e48484614d1a565b915061016083015190509250929050565b60006101008284031215615107578081fd5b6128e38383614dd4565b60008060008385036101e0811215615127578182fd5b6101a080821215615136578283fd5b949694870135955050506101c085013592915050565b60008060008385036101e0811215615162578182fd5b6101a080821215615171578283fd5b61517a81615dc8565b915061518586614e1a565b8252602086015160208301526040860151604083015260608601516060830152608086015160808301526151bb60a08701614cf7565b60a08301526151cc60c08701614cf7565b60c08301526151dd60e08701614ce1565b60e083015261010086810151908301526101208087015190830152610140615206818801614e1a565b908301526101608681015190830152610180615223818801614e1a565b908301528501516101c09095015190969495509392505050565b6000610160828403121561524f578081fd5b6128e38383614d02565b6000610120828403121561526b578081fd5b6128e38383614de6565b6000610120808385031215615288578182fd5b61529181615dc8565b905061529c83614e1a565b81526020830151602082015260408301516040820152606083015160608201526152c860808401614cf7565b60808201526152d960a08401614ce1565b60a082015260c083015160c082015260e083015160e0820152610100615300818501614e1a565b908201529392505050565b6000806040838503121561531d578182fd5b61532683614df8565b915061533460208401614df8565b90509250929050565b60006020828403121561534e578081fd5b5035919050565b600060208284031215615366578081fd5b5051919050565b6000806040838503121561537f578182fd5b505080516020909101519092909150565b6000806000606084860312156153a4578081fd5b8351925060208401519150604084015190509250925092565b6000602082840312156153ce578081fd5b81356128e381615e3b565b6001600160a01b03169052565b15159052565b60008151808452615404816020860160208601615dec565b601f01601f19169290920160200192915050565b6005811061542257fe5b9052565b61543182825161560b565b602081015161544360208401826153e6565b506040810151604083015260608101516060830152608081015161546a60808401826153e6565b5060a081015161547d60a08401826153d9565b5060c081015160c083015260e081015160e0830152610100808201516154a58285018261560b565b5050610120818101519083015261014080820151611f3c8285018261560b565b80356154d081615e18565b6001600160a01b0390811683526020820135906154ec82615e18565b1660208301526040818101359083015260608082013590830152608081013561551481615e2d565b1515608083015260a081013561552981615e18565b61553660a08401826153d9565b5060c081013560c083015261554d60e08201614e0f565b611c9060e084018261560b565b61556582825161560b565b6020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015161559f60a08401826153e6565b5060c08101516155b260c08401826153e6565b5060e08101516155c560e08401826153d9565b5061010081810151908301526101208082015190830152610140808201516155ef8285018261560b565b5050610160818101519083015261018080820151611f3c828501825b63ffffffff169052565b60008251615627818460208701615dec565b9190910192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039687168152948616602086015292851660408501529084166060840152909216608082015260a081019190915260c00190565b6001600160a01b0396871681529486166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b6001600160a01b0396871681529486166020860152604085019390935293166060830152608082019290925290151560a082015260c00190565b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b6001600160a01b03878116825286166020820152604081018590526060810184905261ffff8316608082015260c060a0820181905260009061577d908301846153ec565b98975050505050505050565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b0392909216825261ffff16602082015260400190565b901515815260200190565b60008515158252846020830152836040830152608060608301526157f360808301846153ec565b9695505050505050565b60006060825261581060608301866153ec565b60208301949094525060400152919050565b602081016006831061583057fe5b91905290565b604081016158448285615418565b63ffffffff831660208301529392505050565b6020808252600490820152632a22181b60e11b604082015260600190565b6020808252600490820152635444314360e01b604082015260600190565b60208082526004908201526315110c4d60e21b604082015260600190565b6020808252600490820152635444303360e01b604082015260600190565b6020808252600490820152635444333760e01b604082015260600190565b6020808252600490820152630544430360e41b604082015260600190565b6020808252600490820152630544434360e41b604082015260600190565b60208082526004908201526315110d4d60e21b604082015260600190565b60208082526004908201526315110c0d60e21b604082015260600190565b6020808252600490820152632a221a9960e11b604082015260600190565b6020808252600490820152632a22181960e11b604082015260600190565b6020808252600490820152630a88860760e31b604082015260600190565b6020808252600490820152635444343160e01b604082015260600190565b6020808252600490820152634f53323160e01b604082015260600190565b61016081016127d48284615426565b6101808101615a198285615426565b826101608301529392505050565b90815260200190565b8481526001600160a01b038416602082015260808101615a536040830185615418565b821515606083015295945050505050565b9283526001600160a01b03919091166020830152604082015260600190565b8381526101408101615a9860208301856154c5565b82610120830152949350505050565b8381526101a08101615ac460208301615abf86614cd6565b6153d9565b615ad060208501614cd6565b615add60408401826153d9565b506040840135606083015260608401356080830152608084013560a083015260a084013560c0830152615b1260c08501614cec565b615b1f60e08401826153e6565b50615b2c60e08501614cec565b610100615b3b818501836153e6565b615b46818701614cd6565b915050610120615b58818501836153d9565b6101409150808601358285015250615b71818601614e0f565b9050615b8161016084018261560b565b5082610180830152949350505050565b8281526101408101615ba960208301615abf85614cd6565b615bb560208401614cd6565b615bc260408401826153d9565b506040830135606083015260608301356080830152608083013560a0830152615bed60a08401614cec565b615bfa60c08401826153e6565b50615c0760c08401614cd6565b615c1460e08401826153d9565b5061010060e084013581840152615c2c818501614e0f565b905061459e61012084018261560b565b918252602082015260400190565b9485526001600160a01b0393841660208601526040850192909252606084015216608082015260a00190565b6101a081016127d4828461555a565b6101e08101615c94828661555a565b6101a08201939093526101c00152919050565b60006101208201905063ffffffff835116825260208301516020830152604083015160408301526060830151606083015260808301511515608083015260a0830151615cf660a08401826153d9565b5060c083015160c083015260e083015160e083015261010080840151615d1e8285018261560b565b505092915050565b61ffff91909116815260200190565b60008382526040602083015261449660408301846153ec565b600085825284602083015260018060a01b0384166040830152608060608301526157f360808301846153ec565b600084825283602083015260606040830152615d9a60608301846153ec565b95945050505050565b91825263ffffffff16602082015260400190565b63ffffffff91909116815260200190565b60405181810167ffffffffffffffff81118282101715615de457fe5b604052919050565b60005b83811015615e07578181015183820152602001615def565b83811115611f3c5750506000910152565b6001600160a01b03811681146149ca57600080fd5b80151581146149ca57600080fd5b63ffffffff811681146149ca57600080fdfe13da86008ba1c6922daee3e07db95305ef49ebced9f5467a0b8613fcc6b343e3a26469706673582212209aca9082c087ade6eb58f802c44cd779e0548502d9867d5aa9a7369a3e2d997564736f6c63430007060033000000000000000000000000717ef162cf831db83c51134734a15d1ebe9e516a00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab100000000000000000000000090779545ffbef2e2a2e897b3db7b1d36c05c9e70

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

000000000000000000000000717ef162cf831db83c51134734a15d1ebe9e516a00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab100000000000000000000000090779545ffbef2e2a2e897b3db7b1d36c05c9e70

-----Decoded View---------------
Arg [0] : _factory (address): 0x717ef162cf831db83c51134734a15d1ebe9e516a
Arg [1] : _weth (address): 0x82af49447d8a07e3bd95bd0d56f35241523fbab1
Arg [2] : _bot (address): 0x90779545ffbef2e2a2e897b3db7b1d36c05c9e70

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000717ef162cf831db83c51134734a15d1ebe9e516a
Arg [1] : 00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1
Arg [2] : 00000000000000000000000090779545ffbef2e2a2e897b3db7b1d36c05c9e70


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