ETH Price: $3,390.34 (+1.28%)

Contract

0xc3a99a855D060D727367c599Ecb2423e0bEbEe24
 

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Execute214696062024-12-24 3:19:3516 mins ago1735010375IN
0xc3a99a85...e0bEbEe24
0 ETH0.001856776.20936382
Execute214695222024-12-24 3:02:4732 mins ago1735009367IN
0xc3a99a85...e0bEbEe24
0 ETH0.001796636.20221739
Execute214694682024-12-24 2:51:4743 mins ago1735008707IN
0xc3a99a85...e0bEbEe24
0 ETH0.001709986.23031797
Execute214694282024-12-24 2:43:4751 mins ago1735008227IN
0xc3a99a85...e0bEbEe24
0 ETH0.001342876.25038899
Execute214693522024-12-24 2:28:351 hr ago1735007315IN
0xc3a99a85...e0bEbEe24
0 ETH0.001618146.49159666
Execute214693132024-12-24 2:20:471 hr ago1735006847IN
0xc3a99a85...e0bEbEe24
0 ETH0.001923366.97945058
Execute214691732024-12-24 1:52:471 hr ago1735005167IN
0xc3a99a85...e0bEbEe24
0 ETH0.001605196.18554865
Execute214690042024-12-24 1:18:472 hrs ago1735003127IN
0xc3a99a85...e0bEbEe24
0 ETH0.002126967.98153484
Execute214688322024-12-24 0:43:592 hrs ago1735001039IN
0xc3a99a85...e0bEbEe24
0 ETH0.002201628.26186245
Execute214687292024-12-24 0:22:473 hrs ago1734999767IN
0xc3a99a85...e0bEbEe24
0 ETH0.00356177.38947802
Execute214686882024-12-24 0:14:353 hrs ago1734999275IN
0xc3a99a85...e0bEbEe24
0 ETH0.002308868.84810085
Execute214686262024-12-24 0:01:593 hrs ago1734998519IN
0xc3a99a85...e0bEbEe24
0 ETH0.002465198.98210717
Execute214685792024-12-23 23:52:233 hrs ago1734997943IN
0xc3a99a85...e0bEbEe24
0 ETH0.002183088.05977582
Execute214685602024-12-23 23:48:353 hrs ago1734997715IN
0xc3a99a85...e0bEbEe24
0 ETH0.002201918.93302367
Execute214685012024-12-23 23:36:473 hrs ago1734997007IN
0xc3a99a85...e0bEbEe24
0 ETH0.002505539.41195057
Execute214684882024-12-23 23:34:114 hrs ago1734996851IN
0xc3a99a85...e0bEbEe24
0 ETH0.0030982411.41616758
Execute214684762024-12-23 23:31:474 hrs ago1734996707IN
0xc3a99a85...e0bEbEe24
0 ETH0.0030764410.99100062
Execute214684642024-12-23 23:29:234 hrs ago1734996563IN
0xc3a99a85...e0bEbEe24
0 ETH0.002663969.98104773
Execute214683882024-12-23 23:13:594 hrs ago1734995639IN
0xc3a99a85...e0bEbEe24
0 ETH0.003006311.52106088
Execute214683452024-12-23 23:04:594 hrs ago1734995099IN
0xc3a99a85...e0bEbEe24
0 ETH0.0030043611.06626022
Execute214683122024-12-23 22:58:234 hrs ago1734994703IN
0xc3a99a85...e0bEbEe24
0 ETH0.002668569.83872615
Execute214683052024-12-23 22:56:594 hrs ago1734994619IN
0xc3a99a85...e0bEbEe24
0 ETH0.002592379.76456633
Execute214682982024-12-23 22:55:354 hrs ago1734994535IN
0xc3a99a85...e0bEbEe24
0 ETH0.002522939.8352777
Execute214682862024-12-23 22:53:114 hrs ago1734994391IN
0xc3a99a85...e0bEbEe24
0 ETH0.0028445610.53718794
Execute214682802024-12-23 22:51:594 hrs ago1734994319IN
0xc3a99a85...e0bEbEe24
0 ETH0.002581239.85921106
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
214696062024-12-24 3:19:3516 mins ago1735010375
0xc3a99a85...e0bEbEe24
0.00421638 ETH
214696062024-12-24 3:19:3516 mins ago1735010375
0xc3a99a85...e0bEbEe24
0.00238205 ETH
214695892024-12-24 3:16:1119 mins ago1735010171
0xc3a99a85...e0bEbEe24
0.00654206 ETH
214695432024-12-24 3:06:5928 mins ago1735009619
0xc3a99a85...e0bEbEe24
0.00654206 ETH
214695222024-12-24 3:02:4732 mins ago1735009367
0xc3a99a85...e0bEbEe24
0.00431384 ETH
214695222024-12-24 3:02:4732 mins ago1735009367
0xc3a99a85...e0bEbEe24
0.00230562 ETH
214694682024-12-24 2:51:4743 mins ago1735008707
0xc3a99a85...e0bEbEe24
0.00438163 ETH
214694682024-12-24 2:51:4743 mins ago1735008707
0xc3a99a85...e0bEbEe24
0.00228257 ETH
214694542024-12-24 2:48:5946 mins ago1735008539
0xc3a99a85...e0bEbEe24
0.00659843 ETH
214694282024-12-24 2:43:4751 mins ago1735008227
0xc3a99a85...e0bEbEe24
0.00497515 ETH
214694282024-12-24 2:43:4751 mins ago1735008227
0xc3a99a85...e0bEbEe24
0.00168906 ETH
214693702024-12-24 2:32:111 hr ago1735007531
0xc3a99a85...e0bEbEe24
0.00661946 ETH
214693522024-12-24 2:28:351 hr ago1735007315
0xc3a99a85...e0bEbEe24
0.00464766 ETH
214693522024-12-24 2:28:351 hr ago1735007315
0xc3a99a85...e0bEbEe24
0.00201654 ETH
214693132024-12-24 2:20:471 hr ago1735006847
0xc3a99a85...e0bEbEe24
0.00442202 ETH
214693132024-12-24 2:20:471 hr ago1735006847
0xc3a99a85...e0bEbEe24
0.00227005 ETH
214693102024-12-24 2:20:111 hr ago1735006811
0xc3a99a85...e0bEbEe24
0.00666421 ETH
214692722024-12-24 2:12:351 hr ago1735006355
0xc3a99a85...e0bEbEe24
0.00666421 ETH
214691962024-12-24 1:57:231 hr ago1735005443
0xc3a99a85...e0bEbEe24
0.00666421 ETH
214691732024-12-24 1:52:471 hr ago1735005167
0xc3a99a85...e0bEbEe24
0.00451816 ETH
214691732024-12-24 1:52:471 hr ago1735005167
0xc3a99a85...e0bEbEe24
0.0021739 ETH
214691582024-12-24 1:49:471 hr ago1735004987
0xc3a99a85...e0bEbEe24
0.00669207 ETH
214690192024-12-24 1:21:472 hrs ago1735003307
0xc3a99a85...e0bEbEe24
0.00669207 ETH
214690042024-12-24 1:18:472 hrs ago1735003127
0xc3a99a85...e0bEbEe24
0.00446134 ETH
214690042024-12-24 1:18:472 hrs ago1735003127
0xc3a99a85...e0bEbEe24
0.00224366 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
TwapDelay

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 18 : TwapDelay.sol
pragma solidity 0.7.6;
pragma abicoder v2;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9




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';
import './libraries/ExecutionHelper.sol';
import './interfaces/ITwapFactoryGovernor.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;

    address public override owner;
    address public override factoryGovernor;
    address public constant RELAYER_ADDRESS = 0xd17b3c9784510E33cD5B87b490E79253BcD81e2E; 
    mapping(address => bool) public override isBot;

    constructor(address _factoryGovernor, address _bot) {
        _setOwner(msg.sender);
        _setFactoryGovernor(_factoryGovernor);
        _setBot(_bot, true);

        orders.gasPrice = tx.gasprice;
        _emitEventWithDefaults();
    }

    function getTransferGasCost(address token) external pure override returns (uint256 gasCost) {
        return Orders.getTransferGasCost(token);
    }

    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,
        uint256 validAfterTimestamp
    ) external view override returns (Orders.OrderStatus) {
        return orders.getOrderStatus(orderId, validAfterTimestamp);
    }

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

    function factory() external pure override returns (address) {
        return Orders.FACTORY_ADDRESS;
    }

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

    // returns wrapped native currency for particular blockchain (WETH or WMATIC)
    function weth() external pure override returns (address) {
        return TokenShares.WETH_ADDRESS;
    }

    function relayer() external pure override returns (address) {
        return RELAYER_ADDRESS;
    }

    function isNonRebasingToken(address token) external pure override returns (bool) {
        return TokenShares.isNonRebasing(token);
    }

    function delay() external pure override returns (uint256) {
        return Orders.DELAY;
    }

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

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

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

    function maxGasLimit() external pure override returns (uint256) {
        return Orders.MAX_GAS_LIMIT;
    }

    function maxGasPriceImpact() external pure override returns (uint256) {
        return Orders.MAX_GAS_PRICE_IMPACT;
    }

    function gasPriceInertia() external pure override returns (uint256) {
        return Orders.GAS_PRICE_INERTIA;
    }

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

    function setOrderTypesDisabled(
        address pair,
        Orders.OrderType[] calldata orderTypes,
        bool disabled
    ) external override {
        require(msg.sender == owner, 'TD00');
        orders.setOrderTypesDisabled(pair, orderTypes, disabled);
    }

    function setOwner(address _owner) external override {
        require(msg.sender == owner, 'TD00');
        _setOwner(_owner);
    }

    function _setOwner(address _owner) internal {
        require(_owner != owner, 'TD01');
        require(_owner != address(0), 'TD02');
        owner = _owner;
        emit OwnerSet(_owner);
    }

    function setFactoryGovernor(address _factoryGovernor) external override {
        require(msg.sender == owner, 'TD00');
        _setFactoryGovernor(_factoryGovernor);
    }

    function _setFactoryGovernor(address _factoryGovernor) internal {
        require(_factoryGovernor != factoryGovernor, 'TD01');
        require(_factoryGovernor != address(0), 'TD02');
        factoryGovernor = _factoryGovernor;
        emit FactoryGovernorSet(_factoryGovernor);
    }

    function setBot(address _bot, bool _isBot) external override {
        require(msg.sender == owner, 'TD00');
        _setBot(_bot, _isBot);
    }

    function _setBot(address _bot, bool _isBot) internal {
        require(_isBot != isBot[_bot], 'TD01');
        isBot[_bot] = _isBot;
        emit BotSet(_bot, _isBot);
    }

    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 relayerSell(
        Orders.SellParams calldata sellParams
    ) external payable override lock returns (uint256 orderId) {
        require(msg.sender == RELAYER_ADDRESS, 'TD00');
        orders.relayerSell(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;
    }

    /// @dev This implementation processes orders sequentially and skips orders that have already been executed.
    /// If it encounters an order that is not yet valid, it stops execution since subsequent orders will also be invalid
    /// at the time.
    function execute(Orders.Order[] calldata _orders) external payable override lock {
        uint256 ordersLength = _orders.length;
        uint256 gasBefore = gasleft();
        bool orderExecuted;
        bool senderCanExecute = isBot[msg.sender] || isBot[address(0)];
        for (uint256 i; i < ordersLength; ++i) {
            if (_orders[i].orderId <= orders.lastProcessedOrderId) {
                continue;
            }
            if (orders.canceled[_orders[i].orderId]) {
                orders.dequeueOrder(_orders[i].orderId);
                continue;
            }
            orders.verifyOrder(_orders[i]);
            uint256 validAfterTimestamp = _orders[i].validAfterTimestamp;
            if (validAfterTimestamp >= block.timestamp) {
                break;
            }
            require(senderCanExecute || block.timestamp >= validAfterTimestamp + BOT_EXECUTION_TIME, 'TD00');
            orderExecuted = true;
            if (_orders[i].orderType == Orders.OrderType.Deposit) {
                executeDeposit(_orders[i]);
            } else if (_orders[i].orderType == Orders.OrderType.Withdraw) {
                executeWithdraw(_orders[i]);
            } else if (_orders[i].orderType == Orders.OrderType.Sell) {
                executeSell(_orders[i]);
            } else if (_orders[i].orderType == Orders.OrderType.Buy) {
                executeBuy(_orders[i]);
            }
        }
        if (orderExecuted) {
            orders.updateGasPrice(gasBefore.sub(gasleft()));
        }
    }

    /// @dev The `order` must be verified by calling `Orders.verifyOrder` before calling this function.
    function executeDeposit(Orders.Order calldata order) internal {
        uint256 gasStart = gasleft();
        orders.dequeueOrder(order.orderId);

        (bool executionSuccess, bytes memory data) = address(this).call{
            gas: order.gasLimit.sub(
                Orders.DEPOSIT_ORDER_BASE_COST +
                    Orders.getTransferGasCost(order.token0) +
                    Orders.getTransferGasCost(order.token1)
            )
        }(abi.encodeWithSelector(this._executeDeposit.selector, order));

        bool refundSuccess = true;
        if (!executionSuccess) {
            refundSuccess = refundTokens(
                order.to,
                order.token0,
                order.value0,
                order.token1,
                order.value1,
                order.unwrap,
                false
            );
        }
        finalizeOrder(refundSuccess);
        (uint256 gasUsed, uint256 ethRefund) = refund(order.gasLimit, order.gasPrice, gasStart, order.to);
        emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund);
    }

    /// @dev The `order` must be verified by calling `Orders.verifyOrder` before calling this function.
    function executeWithdraw(Orders.Order calldata order) internal {
        uint256 gasStart = gasleft();
        orders.dequeueOrder(order.orderId);

        (bool executionSuccess, bytes memory data) = address(this).call{
            gas: order.gasLimit.sub(Orders.WITHDRAW_ORDER_BASE_COST + Orders.PAIR_TRANSFER_COST)
        }(abi.encodeWithSelector(this._executeWithdraw.selector, order));

        bool refundSuccess = true;
        if (!executionSuccess) {
            (address pair, ) = Orders.getPair(order.token0, order.token1);
            refundSuccess = Orders.refundLiquidity(pair, order.to, order.liquidity, this._refundLiquidity.selector);
        }
        finalizeOrder(refundSuccess);
        (uint256 gasUsed, uint256 ethRefund) = refund(order.gasLimit, order.gasPrice, gasStart, order.to);
        emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund);
    }

    /// @dev The `order` must be verified by calling `Orders.verifyOrder` before calling this function.
    function executeSell(Orders.Order calldata order) internal {
        uint256 gasStart = gasleft();
        orders.dequeueOrder(order.orderId);

        (bool executionSuccess, bytes memory data) = address(this).call{
            gas: order.gasLimit.sub(Orders.SELL_ORDER_BASE_COST + Orders.getTransferGasCost(order.token0))
        }(abi.encodeWithSelector(this._executeSell.selector, order));

        bool refundSuccess = true;
        if (!executionSuccess) {
            refundSuccess = refundToken(order.token0, order.to, order.value0, order.unwrap, false);
        }
        finalizeOrder(refundSuccess);
        (uint256 gasUsed, uint256 ethRefund) = refund(order.gasLimit, order.gasPrice, gasStart, order.to);
        emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund);
    }

    /// @dev The `order` must be verified by calling `Orders.verifyOrder` before calling this function.
    function executeBuy(Orders.Order calldata order) internal {
        uint256 gasStart = gasleft();
        orders.dequeueOrder(order.orderId);

        (bool executionSuccess, bytes memory data) = address(this).call{
            gas: order.gasLimit.sub(Orders.BUY_ORDER_BASE_COST + Orders.getTransferGasCost(order.token0))
        }(abi.encodeWithSelector(this._executeBuy.selector, order));

        bool refundSuccess = true;
        if (!executionSuccess) {
            refundSuccess = refundToken(order.token0, order.to, order.value0, order.unwrap, false);
        }
        finalizeOrder(refundSuccess);
        (uint256 gasUsed, uint256 ethRefund) = refund(order.gasLimit, order.gasPrice, gasStart, order.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.getTransferGasCost(Orders.NATIVE_CURRENCY_SENTINEL));
        emit EthRefund(to, success, value);
    }

    function refundToken(
        address token,
        address to,
        uint256 share,
        bool unwrap,
        bool forwardAllGas
    ) private returns (bool) {
        if (share == 0) {
            return true;
        }
        (bool success, bytes memory data) = address(this).call{
            gas: forwardAllGas ? gasleft() : Orders.TOKEN_REFUND_BASE_COST + Orders.getTransferGasCost(token)
        }(abi.encodeWithSelector(this._refundToken.selector, token, to, share, unwrap));
        if (!success) {
            emit Orders.RefundFailed(to, token, share, data);
        }
        return success;
    }

    function refundTokens(
        address to,
        address token0,
        uint256 share0,
        address token1,
        uint256 share1,
        bool unwrap,
        bool forwardAllGas
    ) private returns (bool) {
        (bool success, bytes memory data) = address(this).call{
            gas: forwardAllGas
                ? gasleft()
                : 2 *
                    Orders.TOKEN_REFUND_BASE_COST +
                    Orders.getTransferGasCost(token0) +
                    Orders.getTransferGasCost(token1)
        }(abi.encodeWithSelector(this._refundTokens.selector, to, token0, share0, token1, share1, unwrap));
        if (!success) {
            emit Orders.RefundFailed(to, token0, share0, data);
            emit Orders.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_ADDRESS && unwrap) {
            uint256 amount = tokenShares.sharesToAmount(token, share, 0, to);
            IWETH(TokenShares.WETH_ADDRESS).withdraw(amount);
            TransferHelper.safeTransferETH(to, amount, Orders.getTransferGasCost(Orders.NATIVE_CURRENCY_SENTINEL));
        } 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.Order calldata order) external payable {
        require(msg.sender == address(this), 'TD00');

        (address pairAddress, ) = Orders.getPair(order.token0, order.token1);

        ITwapPair(pairAddress).sync();
        ITwapFactoryGovernor(factoryGovernor).distributeFees(order.token0, order.token1, pairAddress);
        ITwapPair(pairAddress).sync();
        ExecutionHelper.executeDeposit(order, pairAddress, getTolerance(pairAddress), tokenShares);
    }

    function _executeWithdraw(Orders.Order calldata order) external payable {
        require(msg.sender == address(this), 'TD00');

        (address pairAddress, ) = Orders.getPair(order.token0, order.token1);

        ITwapPair(pairAddress).sync();
        ITwapFactoryGovernor(factoryGovernor).distributeFees(order.token0, order.token1, pairAddress);
        ITwapPair(pairAddress).sync();
        ExecutionHelper.executeWithdraw(order);
    }

    function _executeBuy(Orders.Order calldata order) external payable {
        require(msg.sender == address(this), 'TD00');

        (address pairAddress, ) = Orders.getPair(order.token0, order.token1);
        ExecutionHelper.ExecuteBuySellParams memory orderParams;
        orderParams.order = order;
        orderParams.pairAddress = pairAddress;
        orderParams.pairTolerance = getTolerance(pairAddress);

        ITwapPair(pairAddress).sync();
        ExecutionHelper.executeBuy(orderParams, tokenShares);
    }

    function _executeSell(Orders.Order calldata order) external payable {
        require(msg.sender == address(this), 'TD00');

        (address pairAddress, ) = Orders.getPair(order.token0, order.token1);
        ExecutionHelper.ExecuteBuySellParams memory orderParams;
        orderParams.order = order;
        orderParams.pairAddress = pairAddress;
        orderParams.pairTolerance = getTolerance(pairAddress);

        ITwapPair(pairAddress).sync();
        ExecutionHelper.executeSell(orderParams, tokenShares);
    }

    /// @dev The `order` must be verified by calling `Orders.verifyOrder` before calling this function.
    function performRefund(Orders.Order calldata order, bool shouldRefundEth) internal {
        bool canOwnerRefund = order.validAfterTimestamp.add(365 days) < block.timestamp;

        if (order.orderType == Orders.OrderType.Deposit) {
            address to = canOwnerRefund ? owner : order.to;
            require(
                refundTokens(to, order.token0, order.value0, order.token1, order.value1, order.unwrap, true),
                'TD14'
            );
            if (shouldRefundEth) {
                require(refundEth(payable(to), order.gasPrice.mul(order.gasLimit)), 'TD40');
            }
        } else if (order.orderType == Orders.OrderType.Withdraw) {
            (address pair, ) = Orders.getPair(order.token0, order.token1);
            address to = canOwnerRefund ? owner : order.to;
            require(Orders.refundLiquidity(pair, to, order.liquidity, this._refundLiquidity.selector), 'TD14');
            if (shouldRefundEth) {
                require(refundEth(payable(to), order.gasPrice.mul(order.gasLimit)), 'TD40');
            }
        } else if (order.orderType == Orders.OrderType.Sell) {
            address to = canOwnerRefund ? owner : order.to;
            require(refundToken(order.token0, to, order.value0, order.unwrap, true), 'TD14');
            if (shouldRefundEth) {
                require(refundEth(payable(to), order.gasPrice.mul(order.gasLimit)), 'TD40');
            }
        } else if (order.orderType == Orders.OrderType.Buy) {
            address to = canOwnerRefund ? owner : order.to;
            require(refundToken(order.token0, to, order.value0, order.unwrap, true), 'TD14');
            if (shouldRefundEth) {
                require(refundEth(payable(to), order.gasPrice.mul(order.gasLimit)), 'TD40');
            }
        } else {
            return;
        }
        orders.forgetOrder(order.orderId);
    }

    function retryRefund(Orders.Order calldata order) external override lock {
        orders.verifyOrder(order);
        require(orders.refundFailed[order.orderId], 'TD21');
        performRefund(order, false);
    }

    function cancelOrder(Orders.Order calldata order) external override lock {
        orders.verifyOrder(order);
        require(
            orders.getOrderStatus(order.orderId, order.validAfterTimestamp) == Orders.OrderStatus.EnqueuedReady,
            'TD52'
        );
        require(order.validAfterTimestamp.sub(Orders.DELAY).add(ORDER_CANCEL_TIME) < block.timestamp, 'TD1C');
        orders.canceled[order.orderId] = true;
        performRefund(order, true);
    }

    function syncPair(address token0, address token1) external override returns (address pairAddress) {
        require(msg.sender == factoryGovernor, 'TD00');

        (pairAddress, ) = Orders.getPair(token0, token1);
        ITwapPair(pairAddress).sync();
    }

    
    function _emitEventWithDefaults() internal {
        emit MaxGasLimitSet(Orders.MAX_GAS_LIMIT);
        emit GasPriceInertiaSet(Orders.GAS_PRICE_INERTIA);
        emit MaxGasPriceImpactSet(Orders.MAX_GAS_PRICE_IMPACT);
        emit DelaySet(Orders.DELAY);
        emit RelayerSet(RELAYER_ADDRESS);

        emit ToleranceSet(0x2fe16Dd18bba26e457B7dD2080d5674312b026a2, 0);
        emit ToleranceSet(0x048f0e7ea2CFD522a4a058D1b1bDd574A0486c46, 0);
        emit ToleranceSet(0x37F6dF71b40c50b2038329CaBf5FDa3682Df1ebF, 0);
        emit ToleranceSet(0x6ec472b613012a492693697FA551420E60567eA7, 0);
        emit ToleranceSet(0x43f0E5f2304F261DfA5359a0b74Ff030E498D904, 0);
        emit ToleranceSet(0xD66f214fB49f81Ac5610e0339A351D7e1c67c35e, 0);
        emit ToleranceSet(0xD4d2140eD70DCF8794A986F0CFD07560ee738C71, 4);
        emit ToleranceSet(0x29b57D56a114aE5BE3c129240898B3321A70A300, 0);
        emit ToleranceSet(0x61fA1CEe13CEEAF20C30611c5e6dA48c595F7dB2, 0);
        emit ToleranceSet(0x045950A37c59d75496BB4Af68c05f9066A4C7e27, 0);
        emit ToleranceSet(0xbEE7Ef1adfaa628536Ebc0C1EBF082DbDC27265F, 0);
        emit ToleranceSet(0x51baDc1622C63d1E448A4F1aC1DC008b8a27Fe67, 0);
        emit ToleranceSet(0x0e52DB138Df9CE54Bc9D9330f418015eD512830A, 0);
        emit ToleranceSet(0xDDE7684D88E0B482B2b455936fe0D22dd48CDcb3, 0);
        emit ToleranceSet(0x43102f07414D95eF71EC9aEbA011b8595BA010D0, 0);

        emit TransferGasCostSet(Orders.NATIVE_CURRENCY_SENTINEL, Orders.ETHER_TRANSFER_CALL_COST);
        emit TransferGasCostSet(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, 31000);
        emit TransferGasCostSet(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48, 42000);
        emit TransferGasCostSet(0xdAC17F958D2ee523a2206206994597C13D831ec7, 66000);
        emit TransferGasCostSet(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599, 34000);
        emit TransferGasCostSet(0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B, 31000);
        emit TransferGasCostSet(0x6B3595068778DD592e39A122f4f5a5cF09C90fE2, 31000);
        emit TransferGasCostSet(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84, 68000);
        emit TransferGasCostSet(0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0, 31000);
        emit TransferGasCostSet(0xD33526068D116cE69F19A9ee46F0bd304F21A51f, 31000);
        emit TransferGasCostSet(0x48C3399719B582dD63eB5AADf12A40B4C3f52FA2, 40000);
        emit TransferGasCostSet(0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32, 149000);
        emit TransferGasCostSet(0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2, 34000);
        emit TransferGasCostSet(0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984, 37000);
        emit TransferGasCostSet(0x514910771AF9Ca656af840dff83E8264EcF986CA, 32000);
        emit TransferGasCostSet(0x3c3a81e81dc49A522A592e7622A7E711c06bf354, 34000);

        emit NonRebasingTokenSet(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, true);
        emit NonRebasingTokenSet(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48, true);
        emit NonRebasingTokenSet(0xdAC17F958D2ee523a2206206994597C13D831ec7, true);
        emit NonRebasingTokenSet(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599, true);
        emit NonRebasingTokenSet(0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B, true);
        emit NonRebasingTokenSet(0x6B3595068778DD592e39A122f4f5a5cF09C90fE2, true);
        emit NonRebasingTokenSet(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84, false);
        emit NonRebasingTokenSet(0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0, true);
        emit NonRebasingTokenSet(0xD33526068D116cE69F19A9ee46F0bd304F21A51f, true);
        emit NonRebasingTokenSet(0x48C3399719B582dD63eB5AADf12A40B4C3f52FA2, true);
        emit NonRebasingTokenSet(0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32, true);
        emit NonRebasingTokenSet(0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2, true);
        emit NonRebasingTokenSet(0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984, true);
        emit NonRebasingTokenSet(0x514910771AF9Ca656af840dff83E8264EcF986CA, true);
        emit NonRebasingTokenSet(0x3c3a81e81dc49A522A592e7622A7E711c06bf354, true);
    }

    
    // constant mapping for tolerance
    function getTolerance(address pair) public virtual view override returns (uint16 tolerance) {
        if (pair == 0xD4d2140eD70DCF8794A986F0CFD07560ee738C71) return 4;
        return 0;
    }

    receive() external payable {}
}

File 2 of 18 : IERC20.sol
pragma solidity 0.7.6;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9



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

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

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

    function decimals() external view returns (uint8);

    function totalSupply() external view returns (uint256);

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

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

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

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

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

File 3 of 18 : IReserves.sol
pragma solidity 0.7.6;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9



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

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

File 4 of 18 : ITwapDelay.sol
pragma solidity 0.7.6;
pragma abicoder v2;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9




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

interface ITwapDelay {
    event OrderExecuted(uint256 indexed id, bool indexed success, bytes data, uint256 gasSpent, uint256 ethRefunded);
    event EthRefund(address indexed to, bool indexed success, uint256 value);
    event OwnerSet(address owner);
    event FactoryGovernorSet(address factoryGovernor);
    event BotSet(address bot, bool isBot);
    event DelaySet(uint256 delay);
    event RelayerSet(address relayer);
    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 NonRebasingTokenSet(address token, bool isNonRebasing);

    function factory() external view returns (address);

    function factoryGovernor() external view returns (address);

    function relayer() external view returns (address);

    function owner() external view returns (address);

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

    function getTolerance(address pair) external view returns (uint16);

    function isNonRebasingToken(address token) external view returns (bool);

    function gasPriceInertia() external view returns (uint256);

    function gasPrice() external view returns (uint256);

    function maxGasPriceImpact() external view returns (uint256);

    function maxGasLimit() external view returns (uint256);

    function delay() external view returns (uint256);

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

    function weth() external view returns (address);

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

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

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

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

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

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

    function setOrderTypesDisabled(address pair, Orders.OrderType[] calldata orderTypes, bool disabled) external;

    function setOwner(address _owner) external;

    function setFactoryGovernor(address _factoryGovernor) external;

    function setBot(address _bot, bool _isBot) external;

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

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

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

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

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

    function execute(Orders.Order[] calldata orders) external payable;

    function retryRefund(Orders.Order calldata order) external;

    function cancelOrder(Orders.Order calldata order) external;

    function syncPair(address token0, address token1) external returns (address pairAddress);
}

File 5 of 18 : ITwapERC20.sol
pragma solidity 0.7.6;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9



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 6 of 18 : ITwapFactory.sol
pragma solidity 0.7.6;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9



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 7 of 18 : ITwapFactoryGovernor.sol
pragma solidity 0.7.6;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9



interface ITwapFactoryGovernor {
    event FactorySet(address factory);
    event DelaySet(address delay);
    event ProtocolFeeRatioSet(uint256 protocolFeeRatio);
    event EthTransferCostSet(uint256 ethTransferCost);
    event FeeDistributed(address indexed token, address indexed pair, uint256 lpAmount, uint256 protocolAmount);
    event OwnerSet(address owner);
    event WithdrawToken(address token, address to, uint256 amount);

    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 factory() external view returns (address);

    function delay() external view returns (address);

    function protocolFeeRatio() external view returns (uint256);

    function ethTransferCost() external view returns (uint256);

    function setFactoryOwner(address) external;

    function setFactory(address) external;

    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 setDelay(address) external;

    function setProtocolFeeRatio(uint256 _protocolFeeRatio) external;

    function setEthTransferCost(uint256 _ethTransferCost) external;

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

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

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

    function withdrawToken(address token, uint256 amount, address to) external;

    function distributeFees(address tokenA, address tokenB) external;

    function distributeFees(address tokenA, address tokenB, address pairAddress) external;

    function feesToDistribute(
        address tokenA,
        address tokenB
    ) external view returns (uint256 fee0ToDistribute, uint256 fee1ToDistribute);
}

File 8 of 18 : ITwapOracle.sol
pragma solidity 0.7.6;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9



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

    function getSpotPrice() external view returns (uint256);

    function getAveragePrice(uint256 priceAccumulator, uint256 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 9 of 18 : ITwapPair.sol
pragma solidity 0.7.6;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9



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

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

    function MINIMUM_LIQUIDITY() external pure returns (uint256);

    function factory() external view returns (address);

    function token0() external view returns (address);

    function token1() external view returns (address);

    function oracle() external view returns (address);

    function trader() external view returns (address);

    function mintFee() external view returns (uint256);

    function setMintFee(uint256 fee) external;

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

    function burnFee() external view returns (uint256);

    function setBurnFee(uint256 fee) external;

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

    function swapFee() external view returns (uint256);

    function setSwapFee(uint256 fee) external;

    function setOracle(address account) external;

    function setTrader(address account) external;

    function collect(address to) external;

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

    function sync() external;

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

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

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

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

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

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

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

File 10 of 18 : IWETH.sol
pragma solidity 0.7.6;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9



interface IWETH {
    function deposit() external payable;

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

    function withdraw(uint256) external;
}

File 11 of 18 : AddLiquidity.sol
pragma solidity 0.7.6;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9



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 12 of 18 : ExecutionHelper.sol
pragma solidity 0.7.6;
pragma abicoder v2;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9




import '../interfaces/ITwapOracle.sol';
import '../interfaces/ITwapPair.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';

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

    using Orders for Orders.Data;
    using TokenShares for TokenShares.Data;

    uint256 private constant ORDER_LIFESPAN = 48 hours;

    struct ExecuteBuySellParams {
        Orders.Order order;
        address pairAddress;
        uint16 pairTolerance;
    }

    function executeDeposit(
        Orders.Order calldata order,
        address pairAddress,
        uint16 pairTolerance,
        TokenShares.Data storage tokenShares
    ) external {
        require(order.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'EH04');

        (uint256 amount0Left, uint256 amount1Left, uint256 swapToken) = _initialDeposit(
            order,
            pairAddress,
            tokenShares
        );

        if (order.swap && swapToken != 0) {
            bytes memory data = encodePriceInfo(pairAddress, order.priceAccumulator, order.timestamp);
            if (amount0Left != 0 && swapToken == 1) {
                uint256 extraAmount1;
                (amount0Left, extraAmount1) = AddLiquidity.swapDeposit0(
                    pairAddress,
                    order.token0,
                    amount0Left,
                    order.minSwapPrice,
                    pairTolerance,
                    data
                );
                amount1Left = amount1Left.add(extraAmount1);
            } else if (amount1Left != 0 && swapToken == 2) {
                uint256 extraAmount0;
                (extraAmount0, amount1Left) = AddLiquidity.swapDeposit1(
                    pairAddress,
                    order.token1,
                    amount1Left,
                    order.maxSwapPrice,
                    pairTolerance,
                    data
                );
                amount0Left = amount0Left.add(extraAmount0);
            }
        }

        if (amount0Left != 0 && amount1Left != 0) {
            (amount0Left, amount1Left, ) = AddLiquidity.addLiquidityAndMint(
                pairAddress,
                order.to,
                order.token0,
                order.token1,
                amount0Left,
                amount1Left
            );
        }

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

    function _initialDeposit(
        Orders.Order calldata order,
        address pairAddress,
        TokenShares.Data storage tokenShares
    ) private returns (uint256 amount0Left, uint256 amount1Left, uint256 swapToken) {
        uint256 amount0Desired = tokenShares.sharesToAmount(order.token0, order.value0, order.amountLimit0, order.to);
        uint256 amount1Desired = tokenShares.sharesToAmount(order.token1, order.value1, order.amountLimit1, order.to);
        (amount0Left, amount1Left, swapToken) = AddLiquidity.addLiquidityAndMint(
            pairAddress,
            order.to,
            order.token0,
            order.token1,
            amount0Desired,
            amount1Desired
        );
    }

    function executeWithdraw(Orders.Order calldata order) external {
        require(order.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'EH04');
        (address pairAddress, ) = Orders.getPair(order.token0, order.token1);
        TransferHelper.safeTransfer(pairAddress, pairAddress, order.liquidity);
        uint256 wethAmount;
        uint256 amount0;
        uint256 amount1;
        if (order.unwrap && (order.token0 == TokenShares.WETH_ADDRESS || order.token1 == TokenShares.WETH_ADDRESS)) {
            bool success;
            (success, wethAmount, amount0, amount1) = WithdrawHelper.withdrawAndUnwrap(
                order.token0,
                order.token1,
                pairAddress,
                TokenShares.WETH_ADDRESS,
                order.to,
                Orders.getTransferGasCost(Orders.NATIVE_CURRENCY_SENTINEL)
            );
            if (!success) {
                TokenShares.onUnwrapFailed(order.to, wethAmount);
            }
        } else {
            (amount0, amount1) = ITwapPair(pairAddress).burn(order.to);
        }
        require(amount0 >= order.value0 && amount1 >= order.value1, 'EH03');
    }

    function executeBuy(ExecuteBuySellParams memory orderParams, TokenShares.Data storage tokenShares) external {
        require(orderParams.order.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'EH04');

        uint256 amountInMax = tokenShares.sharesToAmount(
            orderParams.order.token0,
            orderParams.order.value0,
            orderParams.order.amountLimit0,
            orderParams.order.to
        );
        bytes memory priceInfo = encodePriceInfo(
            orderParams.pairAddress,
            orderParams.order.priceAccumulator,
            orderParams.order.timestamp
        );
        uint256 amountIn;
        uint256 amountOut;
        uint256 reserveOut;
        bool inverted = orderParams.order.inverted;
        {
            // scope for reserve out logic, avoids stack too deep errors
            (uint112 reserve0, uint112 reserve1) = ITwapPair(orderParams.pairAddress).getReserves();
            // subtract 1 to prevent reserve going to 0
            reserveOut = uint256(inverted ? reserve0 : reserve1).sub(1);
        }
        {
            // scope for partial fill logic, avoids stack too deep errors
            address oracle = ITwapPair(orderParams.pairAddress).oracle();
            uint256 swapFee = ITwapPair(orderParams.pairAddress).swapFee();
            (amountIn, amountOut) = ITwapOracle(oracle).getSwapAmountInMaxOut(
                inverted,
                swapFee,
                orderParams.order.value1,
                priceInfo
            );
            uint256 amountInMaxScaled;
            if (amountOut > reserveOut) {
                amountInMaxScaled = amountInMax.mul(reserveOut).ceil_div(orderParams.order.value1);
                (amountIn, amountOut) = ITwapOracle(oracle).getSwapAmountInMinOut(
                    inverted,
                    swapFee,
                    reserveOut,
                    priceInfo
                );
            } else {
                amountInMaxScaled = amountInMax;
                amountOut = orderParams.order.value1; // Truncate to desired out
            }
            require(amountInMaxScaled >= amountIn, 'EH08');
            if (amountInMax > amountIn) {
                if (orderParams.order.token0 == TokenShares.WETH_ADDRESS && orderParams.order.unwrap) {
                    forceEtherTransfer(orderParams.order.to, amountInMax.sub(amountIn));
                } else {
                    TransferHelper.safeTransfer(
                        orderParams.order.token0,
                        orderParams.order.to,
                        amountInMax.sub(amountIn)
                    );
                }
            }
            TransferHelper.safeTransfer(orderParams.order.token0, orderParams.pairAddress, amountIn);
        }
        amountOut = amountOut.sub(orderParams.pairTolerance);
        uint256 amount0Out;
        uint256 amount1Out;
        if (inverted) {
            amount0Out = amountOut;
        } else {
            amount1Out = amountOut;
        }
        if (orderParams.order.token1 == TokenShares.WETH_ADDRESS && orderParams.order.unwrap) {
            ITwapPair(orderParams.pairAddress).swap(amount0Out, amount1Out, address(this), priceInfo);
            forceEtherTransfer(orderParams.order.to, amountOut);
        } else {
            ITwapPair(orderParams.pairAddress).swap(amount0Out, amount1Out, orderParams.order.to, priceInfo);
        }
    }

    function executeSell(ExecuteBuySellParams memory orderParams, TokenShares.Data storage tokenShares) external {
        require(orderParams.order.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'EH04');

        bytes memory priceInfo = encodePriceInfo(
            orderParams.pairAddress,
            orderParams.order.priceAccumulator,
            orderParams.order.timestamp
        );

        uint256 amountOut = _executeSellHelper(orderParams, priceInfo, tokenShares);

        (uint256 amount0Out, uint256 amount1Out) = orderParams.order.inverted
            ? (amountOut, uint256(0))
            : (uint256(0), amountOut);
        if (orderParams.order.token1 == TokenShares.WETH_ADDRESS && orderParams.order.unwrap) {
            ITwapPair(orderParams.pairAddress).swap(amount0Out, amount1Out, address(this), priceInfo);
            forceEtherTransfer(orderParams.order.to, amountOut);
        } else {
            ITwapPair(orderParams.pairAddress).swap(amount0Out, amount1Out, orderParams.order.to, priceInfo);
        }
    }

    function _executeSellHelper(
        ExecuteBuySellParams memory orderParams,
        bytes memory priceInfo,
        TokenShares.Data storage tokenShares
    ) internal returns (uint256 amountOut) {
        uint256 reserveOut;
        {
            // scope for determining reserve out, avoids stack too deep errors
            (uint112 reserve0, uint112 reserve1) = ITwapPair(orderParams.pairAddress).getReserves();
            // subtract 1 to prevent reserve going to 0
            reserveOut = uint256(orderParams.order.inverted ? reserve0 : reserve1).sub(1);
        }
        {
            // scope for calculations, avoids stack too deep errors
            address oracle = ITwapPair(orderParams.pairAddress).oracle();
            uint256 swapFee = ITwapPair(orderParams.pairAddress).swapFee();
            uint256 amountIn = tokenShares.sharesToAmount(
                orderParams.order.token0,
                orderParams.order.value0,
                orderParams.order.amountLimit0,
                orderParams.order.to
            );
            amountOut = orderParams.order.inverted
                ? ITwapOracle(oracle).getSwapAmount0Out(swapFee, amountIn, priceInfo)
                : ITwapOracle(oracle).getSwapAmount1Out(swapFee, amountIn, priceInfo);

            uint256 amountOutMinScaled;
            if (amountOut > reserveOut) {
                amountOutMinScaled = orderParams.order.value1.mul(reserveOut).div(amountOut);
                uint256 _amountIn = amountIn;
                (amountIn, amountOut) = ITwapOracle(oracle).getSwapAmountInMinOut(
                    orderParams.order.inverted,
                    swapFee,
                    reserveOut,
                    priceInfo
                );
                if (orderParams.order.token0 == TokenShares.WETH_ADDRESS && orderParams.order.unwrap) {
                    forceEtherTransfer(orderParams.order.to, _amountIn.sub(amountIn));
                } else {
                    TransferHelper.safeTransfer(
                        orderParams.order.token0,
                        orderParams.order.to,
                        _amountIn.sub(amountIn)
                    );
                }
            } else {
                amountOutMinScaled = orderParams.order.value1;
            }
            amountOut = amountOut.sub(orderParams.pairTolerance);
            require(amountOut >= amountOutMinScaled, 'EH37');
            TransferHelper.safeTransfer(orderParams.order.token0, orderParams.pairAddress, amountIn);
        }
    }

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

    function forceEtherTransfer(address to, uint256 amount) internal {
        IWETH(TokenShares.WETH_ADDRESS).withdraw(amount);
        (bool success, ) = to.call{ value: amount, gas: Orders.getTransferGasCost(Orders.NATIVE_CURRENCY_SENTINEL) }(
            ''
        );
        if (!success) {
            TokenShares.onUnwrapFailed(to, amount);
        }
    }
}

File 13 of 18 : Math.sol
pragma solidity 0.7.6;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9



// 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 18 : Orders.sol
pragma solidity 0.7.6;
pragma abicoder v2;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9




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 DepositEnqueued(uint256 indexed orderId, Order order);
    event WithdrawEnqueued(uint256 indexed orderId, Order order);
    event SellEnqueued(uint256 indexed orderId, Order order);
    event BuyEnqueued(uint256 indexed orderId, Order order);

    event OrderTypesDisabled(address pair, Orders.OrderType[] orderTypes, bool disabled);

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

    // Note on gas estimation for the full order execution in the UI:
    // Add (*_ORDER_BASE_COST + token transfer costs) to the actual gas usage
    // of the TwapDelay._execute* functions when updating gas cost in the UI.
    // Remember that ETH unwrap is part of those functions. It is optional,
    // but also needs to be included in the estimate.

    uint256 public constant ETHER_TRANSFER_COST = ETHER_TRANSFER_CALL_COST + 2600 + 1504; // Std cost + EIP-2929 acct access cost + Gnosis Safe receive ETH cost
    uint256 private constant BOT_ETHER_TRANSFER_COST = 10_000;
    uint256 private constant BUFFER_COST = 10_000;
    uint256 private constant ORDER_EXECUTED_EVENT_COST = 3700;
    uint256 private constant EXECUTE_PREPARATION_COST = 30_000; // dequeue + gas calculation before calls to _execute* functions

    uint256 public constant ETHER_TRANSFER_CALL_COST = 10_000;
    uint256 public constant PAIR_TRANSFER_COST = 55_000;
    uint256 public constant REFUND_BASE_COST =
        BOT_ETHER_TRANSFER_COST + ETHER_TRANSFER_COST + BUFFER_COST + ORDER_EXECUTED_EVENT_COST;
    uint256 private constant ORDER_BASE_COST = EXECUTE_PREPARATION_COST + REFUND_BASE_COST;
    uint256 public constant TOKEN_REFUND_BASE_COST = 20_000; // cost of performing token refund logic (excluding token transfer)

    uint256 public constant DEPOSIT_ORDER_BASE_COST = ORDER_BASE_COST + 2 * TOKEN_REFUND_BASE_COST;
    uint256 public constant WITHDRAW_ORDER_BASE_COST = ORDER_BASE_COST;
    uint256 public constant SELL_ORDER_BASE_COST = ORDER_BASE_COST + TOKEN_REFUND_BASE_COST;
    uint256 public constant BUY_ORDER_BASE_COST = ORDER_BASE_COST + TOKEN_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

    address public constant FACTORY_ADDRESS = 0xC480b33eE5229DE3FbDFAD1D2DCD3F3BAD0C56c6; 
    uint256 public constant MAX_GAS_LIMIT = 5000000; 
    uint256 public constant GAS_PRICE_INERTIA = 20000000; 
    uint256 public constant MAX_GAS_PRICE_IMPACT = 1000000; 
    uint256 public constant DELAY = 1800; 

    address public constant NATIVE_CURRENCY_SENTINEL = address(0); // A sentinel value for the native currency to distinguish it from ERC20 tokens

    struct Data {
        uint256 newestOrderId;
        uint256 lastProcessedOrderId;
        mapping(uint256 => bytes32) orderQueue;
        uint256 gasPrice;
        mapping(uint256 => bool) canceled;
        // Bit on specific positions indicates whether order type is disabled (1) or enabled (0) on specific pair
        mapping(address => uint8) orderTypesDisabled;
        mapping(uint256 => bool) refundFailed;
    }

    struct Order {
        uint256 orderId;
        OrderType orderType;
        bool inverted;
        uint256 validAfterTimestamp;
        bool unwrap;
        uint256 timestamp;
        uint256 gasLimit;
        uint256 gasPrice;
        uint256 liquidity;
        uint256 value0; // Deposit: share0, Withdraw: amount0Min, Sell: shareIn, Buy: shareInMax
        uint256 value1; // Deposit: share1, Withdraw: amount1Min, Sell: amountOutMin, Buy: amountOut
        address token0; // Sell: tokenIn, Buy: tokenIn
        address token1; // Sell: tokenOut, Buy: tokenOut
        address to;
        uint256 minSwapPrice;
        uint256 maxSwapPrice;
        bool swap;
        uint256 priceAccumulator;
        uint256 amountLimit0;
        uint256 amountLimit1;
    }

    function getOrderStatus(
        Data storage data,
        uint256 orderId,
        uint256 validAfterTimestamp
    ) internal view returns (OrderStatus) {
        if (orderId > data.newestOrderId) {
            return OrderStatus.NonExistent;
        }
        if (data.canceled[orderId]) {
            return OrderStatus.Canceled;
        }
        if (data.refundFailed[orderId]) {
            return OrderStatus.ExecutedFailed;
        }
        if (data.orderQueue[orderId] == bytes32(0)) {
            return OrderStatus.ExecutedSucceeded;
        }
        if (validAfterTimestamp >= block.timestamp) {
            return OrderStatus.EnqueuedWaiting;
        }
        return OrderStatus.EnqueuedReady;
    }

    function getPair(address tokenA, address tokenB) internal view returns (address pair, bool inverted) {
        pair = ITwapFactory(FACTORY_ADDRESS).getPair(tokenA, tokenB);
        require(pair != address(0), 'OS17');
        inverted = tokenA > tokenB;
    }

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

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

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

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

    function setOrderTypesDisabled(
        Data storage data,
        address pair,
        Orders.OrderType[] calldata orderTypes,
        bool disabled
    ) external {
        uint256 orderTypesLength = orderTypes.length;
        uint8 currentSettings = data.orderTypesDisabled[pair];

        uint8 combinedMask;
        for (uint256 i; i < orderTypesLength; ++i) {
            Orders.OrderType orderType = orderTypes[i];
            require(orderType != Orders.OrderType.Empty, 'OS32');
            // zeros with 1 bit set at position specified by orderType
            // e.g. for SELL order type
            // mask for SELL    = 00001000
            // combinedMask     = 00000110 (DEPOSIT and WITHDRAW masks set in previous iterations)
            // the result of OR = 00001110 (DEPOSIT, WITHDRAW and SELL combined mask)
            combinedMask = combinedMask | 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 | combinedMask;
        } 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 & (combinedMask ^ 0xff);
        }
        require(currentSettings != data.orderTypesDisabled[pair], 'OS01');
        data.orderTypesDisabled[pair] = currentSettings;

        emit OrderTypesDisabled(pair, orderTypes, disabled);
    }

    function markRefundFailed(Data storage data) internal {
        data.refundFailed[data.lastProcessedOrderId] = true;
    }

    /// @dev The passed in order.oderId is ignored and overwritten with the correct value, i.e. an updated data.newestOrderId.
    /// This is done to ensure atomicity of these two actions while optimizing gas usage - adding an order to the queue and incrementing
    /// data.newestOrderId (which should not be done anywhere else in the contract).
    /// Must only be called on verified orders.
    function enqueueOrder(Data storage data, Order memory order) internal {
        order.orderId = ++data.newestOrderId;
        data.orderQueue[order.orderId] = getOrderDigest(order);
    }

    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 {
        checkOrderParams(
            depositParams.to,
            depositParams.gasLimit,
            depositParams.submitDeadline,
            DEPOSIT_ORDER_BASE_COST +
                getTransferGasCost(depositParams.token0) +
                getTransferGasCost(depositParams.token1)
        );
        require(depositParams.amount0 != 0 || depositParams.amount1 != 0, 'OS25');
        (address pairAddress, bool inverted) = getPair(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_ADDRESS) {
                    value = msg.value.sub(depositParams.amount0, 'OS1E');
                } else if (depositParams.token1 == TokenShares.WETH_ADDRESS) {
                    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, uint256 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo();

        Order memory order = Order(
            0,
            OrderType.Deposit,
            inverted,
            timestamp + DELAY, // validAfterTimestamp
            depositParams.wrap,
            timestamp,
            depositParams.gasLimit,
            data.gasPrice,
            0, // liquidity
            shares0,
            shares1,
            inverted ? depositParams.token1 : depositParams.token0,
            inverted ? depositParams.token0 : depositParams.token1,
            depositParams.to,
            depositParams.minSwapPrice,
            depositParams.maxSwapPrice,
            depositParams.swap,
            priceAccumulator,
            inverted ? depositParams.amount1 : depositParams.amount0,
            inverted ? depositParams.amount0 : depositParams.amount1
        );
        enqueueOrder(data, order);

        emit DepositEnqueued(order.orderId, order);
    }

    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, bool inverted) = getPair(withdrawParams.token0, withdrawParams.token1);
        require(!getWithdrawDisabled(data, pair), 'OS0A');
        checkOrderParams(
            withdrawParams.to,
            withdrawParams.gasLimit,
            withdrawParams.submitDeadline,
            WITHDRAW_ORDER_BASE_COST + PAIR_TRANSFER_COST
        );
        require(withdrawParams.liquidity != 0, 'OS22');

        allocateGasRefund(data, msg.value, withdrawParams.gasLimit);
        pair.safeTransferFrom(msg.sender, address(this), withdrawParams.liquidity);

        Order memory order = Order(
            0,
            OrderType.Withdraw,
            inverted,
            block.timestamp + DELAY, // validAfterTimestamp
            withdrawParams.unwrap,
            0, // timestamp
            withdrawParams.gasLimit,
            data.gasPrice,
            withdrawParams.liquidity,
            inverted ? withdrawParams.amount1Min : withdrawParams.amount0Min,
            inverted ? withdrawParams.amount0Min : withdrawParams.amount1Min,
            inverted ? withdrawParams.token1 : withdrawParams.token0,
            inverted ? withdrawParams.token0 : withdrawParams.token1,
            withdrawParams.to,
            0, // minSwapPrice
            0, // maxSwapPrice
            false, // swap
            0, // priceAccumulator
            0, // amountLimit0
            0 // amountLimit1
        );
        enqueueOrder(data, order);

        emit WithdrawEnqueued(order.orderId, order);
    }

    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 {
        checkOrderParams(
            sellParams.to,
            sellParams.gasLimit,
            sellParams.submitDeadline,
            SELL_ORDER_BASE_COST + getTransferGasCost(sellParams.tokenIn)
        );

        (address pairAddress, bool inverted) = sellHelper(data, sellParams);

        (uint256 priceAccumulator, uint256 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo();

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

        Order memory order = Order(
            0,
            OrderType.Sell,
            inverted,
            timestamp + DELAY, // validAfterTimestamp
            sellParams.wrapUnwrap,
            timestamp,
            sellParams.gasLimit,
            data.gasPrice,
            0, // liquidity
            shares,
            sellParams.amountOutMin,
            sellParams.tokenIn,
            sellParams.tokenOut,
            sellParams.to,
            0, // minSwapPrice
            0, // maxSwapPrice
            false, // swap
            priceAccumulator,
            sellParams.amountIn,
            0 // amountLimit1
        );
        enqueueOrder(data, order);

        emit SellEnqueued(order.orderId, order);
    }

    function relayerSell(
        Data storage data,
        SellParams calldata sellParams,
        TokenShares.Data storage tokenShares
    ) external {
        checkOrderParams(
            sellParams.to,
            sellParams.gasLimit,
            sellParams.submitDeadline,
            SELL_ORDER_BASE_COST + getTransferGasCost(sellParams.tokenIn)
        );

        (, bool inverted) = sellHelper(data, sellParams);

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

        Order memory order = Order(
            0,
            OrderType.Sell,
            inverted,
            block.timestamp + DELAY, // validAfterTimestamp
            false, // Never wrap/unwrap
            block.timestamp,
            sellParams.gasLimit,
            data.gasPrice,
            0, // liquidity
            shares,
            sellParams.amountOutMin,
            sellParams.tokenIn,
            sellParams.tokenOut,
            sellParams.to,
            0, // minSwapPrice
            0, // maxSwapPrice
            false, // swap
            0, // priceAccumulator - oracleV3 pairs don't need priceAccumulator
            sellParams.amountIn,
            0 // amountLimit1
        );
        enqueueOrder(data, order);

        emit SellEnqueued(order.orderId, order);
    }

    function sellHelper(
        Data storage data,
        SellParams calldata sellParams
    ) internal returns (address pairAddress, bool inverted) {
        require(sellParams.amountIn != 0, 'OS24');
        (pairAddress, inverted) = getPair(sellParams.tokenIn, sellParams.tokenOut);
        require(!getSellDisabled(data, pairAddress), 'OS13');

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

    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 {
        checkOrderParams(
            buyParams.to,
            buyParams.gasLimit,
            buyParams.submitDeadline,
            BUY_ORDER_BASE_COST + getTransferGasCost(buyParams.tokenIn)
        );
        require(buyParams.amountOut != 0, 'OS23');
        (address pairAddress, bool inverted) = getPair(buyParams.tokenIn, buyParams.tokenOut);
        require(!getBuyDisabled(data, pairAddress), 'OS49');
        uint256 value = msg.value;

        // allocate gas refund
        if (buyParams.tokenIn == TokenShares.WETH_ADDRESS && 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, uint256 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo();

        Order memory order = Order(
            0,
            OrderType.Buy,
            inverted,
            timestamp + DELAY, // validAfterTimestamp
            buyParams.wrapUnwrap,
            timestamp,
            buyParams.gasLimit,
            data.gasPrice,
            0, // liquidity
            shares,
            buyParams.amountOut,
            buyParams.tokenIn,
            buyParams.tokenOut,
            buyParams.to,
            0, // minSwapPrice
            0, // maxSwapPrice
            false, // swap
            priceAccumulator,
            buyParams.amountInMax,
            0 // amountLimit1
        );
        enqueueOrder(data, order);

        emit BuyEnqueued(order.orderId, order);
    }

    function checkOrderParams(address to, uint256 gasLimit, uint32 submitDeadline, uint256 minGasLimit) private view {
        require(submitDeadline >= block.timestamp, 'OS04');
        require(gasLimit <= MAX_GAS_LIMIT, '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 - futureFee, getTransferGasCost(NATIVE_CURRENCY_SENTINEL));
        }
    }

    function updateGasPrice(Data storage data, uint256 gasUsed) external {
        uint256 scale = Math.min(gasUsed, MAX_GAS_PRICE_IMPACT);
        data.gasPrice = data.gasPrice.mul(GAS_PRICE_INERTIA.sub(scale)).add(tx.gasprice.mul(scale)).div(
            GAS_PRICE_INERTIA
        );
    }

    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 dequeueOrder(Data storage data, uint256 orderId) internal {
        ++data.lastProcessedOrderId;
        require(orderId == data.lastProcessedOrderId, 'OS72');
    }

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

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

    function getOrderDigest(Order memory order) internal pure returns (bytes32) {
        // Used to avoid the 'stack too deep' error.
        bytes memory partialOrderData = abi.encodePacked(
            order.orderId,
            order.orderType,
            order.inverted,
            order.validAfterTimestamp,
            order.unwrap,
            order.timestamp,
            order.gasLimit,
            order.gasPrice,
            order.liquidity,
            order.value0,
            order.value1,
            order.token0,
            order.token1,
            order.to
        );

        return
            keccak256(
                abi.encodePacked(
                    partialOrderData,
                    order.minSwapPrice,
                    order.maxSwapPrice,
                    order.swap,
                    order.priceAccumulator,
                    order.amountLimit0,
                    order.amountLimit1
                )
            );
    }

    function verifyOrder(Data storage data, Order memory order) external view {
        require(getOrderDigest(order) == data.orderQueue[order.orderId], 'OS71');
    }

    
    // constant mapping for transferGasCost
    /**
     * @dev This function should either return a default value != 0 or revert.
     */
    function getTransferGasCost(address token) internal pure returns (uint256) {
        if (token == NATIVE_CURRENCY_SENTINEL) return ETHER_TRANSFER_CALL_COST;
        if (token == 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) return 31000;
        if (token == 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48) return 42000;
        if (token == 0xdAC17F958D2ee523a2206206994597C13D831ec7) return 66000;
        if (token == 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599) return 34000;
        if (token == 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B) return 31000;
        if (token == 0x6B3595068778DD592e39A122f4f5a5cF09C90fE2) return 31000;
        if (token == 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84) return 68000;
        if (token == 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0) return 31000;
        if (token == 0xD33526068D116cE69F19A9ee46F0bd304F21A51f) return 31000;
        if (token == 0x48C3399719B582dD63eB5AADf12A40B4C3f52FA2) return 40000;
        if (token == 0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32) return 149000;
        if (token == 0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2) return 34000;
        if (token == 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984) return 37000;
        if (token == 0x514910771AF9Ca656af840dff83E8264EcF986CA) return 32000;
        if (token == 0x3c3a81e81dc49A522A592e7622A7E711c06bf354) return 34000;
        return 60000;
    }
}

File 15 of 18 : SafeMath.sol
pragma solidity 0.7.6;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9



// 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 toUint64(uint256 n) internal pure returns (uint64) {
        require(n <= type(uint64).max, 'SM54');
        return uint64(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 16 of 18 : TokenShares.sol
pragma solidity 0.7.6;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9



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;
    uint256 private constant TOTAL_SHARES_PRECISION = 10 ** 18;

    event UnwrapFailed(address to, uint256 amount);

    // represents wrapped native currency (WETH or WMATIC)
    address public constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; 

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

    function sharesToAmount(
        Data storage data,
        address token,
        uint256 share,
        uint256 amountLimit,
        address refundTo
    ) external returns (uint256) {
        if (share == 0) {
            return 0;
        }
        if (token == WETH_ADDRESS || isNonRebasing(token)) {
            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 == WETH_ADDRESS) {
            if (wrap) {
                require(msg.value >= amount, 'TS03');
                IWETH(token).deposit{ value: amount }();
            } else {
                token.safeTransferFrom(msg.sender, address(this), amount);
            }
            return amount;
        } else if (isNonRebasing(token)) {
            token.safeTransferFrom(msg.sender, address(this), amount);
            return amount;
        } else {
            uint256 balanceBefore = IERC20(token).balanceOf(address(this));
            token.safeTransferFrom(msg.sender, address(this), amount);
            uint256 balanceAfter = IERC20(token).balanceOf(address(this));

            return amountToSharesHelper(data, token, balanceBefore, balanceAfter);
        }
    }

    function amountToSharesWithoutTransfer(
        Data storage data,
        address token,
        uint256 amount,
        bool wrap
    ) external returns (uint256) {
        if (token == WETH_ADDRESS) {
            if (wrap) {
                // require(msg.value >= amount, 'TS03'); // Duplicate check in TwapRelayer.sell
                IWETH(token).deposit{ value: amount }();
            }
            return amount;
        } else if (isNonRebasing(token)) {
            return amount;
        } else {
            uint256 balanceAfter = IERC20(token).balanceOf(address(this));
            uint256 balanceBefore = balanceAfter.sub(amount);
            return amountToSharesHelper(data, token, balanceBefore, balanceAfter);
        }
    }

    function amountToSharesHelper(
        Data storage data,
        address token,
        uint256 balanceBefore,
        uint256 balanceAfter
    ) internal returns (uint256) {
        uint256 totalTokenShares = data.totalShares[token];
        require(balanceBefore > 0 || totalTokenShares == 0, 'TS30');
        require(balanceAfter > balanceBefore, 'TS2C');

        if (balanceBefore > 0) {
            if (totalTokenShares == 0) {
                totalTokenShares = balanceBefore.mul(TOTAL_SHARES_PRECISION);
            }
            uint256 newShares = totalTokenShares.mul(balanceAfter).div(balanceBefore);
            require(balanceAfter < type(uint256).max.div(newShares), 'TS73'); // to prevent overflow at execution
            data.totalShares[token] = newShares;
            return newShares - totalTokenShares;
        } else {
            totalTokenShares = balanceAfter.mul(TOTAL_SHARES_PRECISION);
            require(totalTokenShares < type(uint256).max.div(totalTokenShares), 'TS73'); // to prevent overflow at execution
            data.totalShares[token] = totalTokenShares;
            return totalTokenShares;
        }
    }

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

    
    // constant mapping for nonRebasingToken
    function isNonRebasing(address token) internal pure returns (bool) {
        if (token == 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) return true;
        if (token == 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48) return true;
        if (token == 0xdAC17F958D2ee523a2206206994597C13D831ec7) return true;
        if (token == 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599) return true;
        if (token == 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B) return true;
        if (token == 0x6B3595068778DD592e39A122f4f5a5cF09C90fE2) return true;
        if (token == 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0) return true;
        if (token == 0xD33526068D116cE69F19A9ee46F0bd304F21A51f) return true;
        if (token == 0x48C3399719B582dD63eB5AADf12A40B4C3f52FA2) return true;
        if (token == 0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32) return true;
        if (token == 0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2) return true;
        if (token == 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984) return true;
        if (token == 0x514910771AF9Ca656af840dff83E8264EcF986CA) return true;
        if (token == 0x3c3a81e81dc49A522A592e7622A7E711c06bf354) return true;
        return false;
    }
}

File 17 of 18 : TransferHelper.sol
pragma solidity 0.7.6;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9



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

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

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

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

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

File 18 of 18 : WithdrawHelper.sol
pragma solidity 0.7.6;
pragma abicoder v2;

// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9




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

    // unwraps wrapped native currency
    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);
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {
    "contracts/libraries/ExecutionHelper.sol": {
      "ExecutionHelper": "0x4a1dbc839b4ebad8db9058e856e90cb41dffce1f"
    },
    "contracts/libraries/Orders.sol": {
      "Orders": "0x465e0b6518603e0d75b4737dac052845cf855925"
    },
    "contracts/libraries/TokenShares.sol": {
      "TokenShares": "0xe92b1734fc37f8acc950d0d13a41475372958730"
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_factoryGovernor","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":"factoryGovernor","type":"address"}],"name":"FactoryGovernorSet","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":"token","type":"address"},{"indexed":false,"internalType":"bool","name":"isNonRebasing","type":"bool"}],"name":"NonRebasingTokenSet","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":false,"internalType":"address","name":"relayer","type":"address"}],"name":"RelayerSet","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"},{"inputs":[],"name":"RELAYER_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"inverted","type":"bool"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"_executeBuy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"inverted","type":"bool"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"_executeDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"inverted","type":"bool"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"_executeSell","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"inverted","type":"bool"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","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":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"inverted","type":"bool"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","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":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"inverted","type":"bool"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order[]","name":"_orders","type":"tuple[]"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"factoryGovernor","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":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getBuyDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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"},{"internalType":"uint256","name":"validAfterTimestamp","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":"address","name":"pair","type":"address"}],"name":"getTolerance","outputs":[{"internalType":"uint16","name":"tolerance","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTransferGasCost","outputs":[{"internalType":"uint256","name":"gasCost","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getWithdrawDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isBot","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"isNonRebasingToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","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":"pure","type":"function"},{"inputs":[],"name":"maxGasPriceImpact","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","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":[],"name":"relayer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","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":"relayerSell","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"inverted","type":"bool"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"retryRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"wrapUnwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.SellParams","name":"sellParams","type":"tuple"}],"name":"sell","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_bot","type":"address"},{"internalType":"bool","name":"_isBot","type":"bool"}],"name":"setBot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_factoryGovernor","type":"address"}],"name":"setFactoryGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"},{"internalType":"enum Orders.OrderType[]","name":"orderTypes","type":"uint8[]"},{"internalType":"bool","name":"disabled","type":"bool"}],"name":"setOrderTypesDisabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"name":"syncPair","outputs":[{"internalType":"address","name":"pairAddress","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","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"}]

60806040526001600b553480156200001657600080fd5b50604051620053da380380620053da833981016040819052620000399162000f28565b620000443362000072565b6200004f826200012d565b6200005c816001620001d4565b3a6003556200006a6200027a565b505062001009565b6008546001600160a01b0382811691161415620000ac5760405162461bcd60e51b8152600401620000a39062000fc4565b60405180910390fd5b6001600160a01b038116620000d55760405162461bcd60e51b8152600401620000a39062000fe2565b600880546001600160a01b0319166001600160a01b0383161790556040517f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe2906200012290839062000f5f565b60405180910390a150565b6009546001600160a01b03828116911614156200015e5760405162461bcd60e51b8152600401620000a39062000fc4565b6001600160a01b038116620001875760405162461bcd60e51b8152600401620000a39062000fe2565b600980546001600160a01b0319166001600160a01b0383161790556040517f99db624faf5b574db8409c17138c4894a18b552e2cd1dbe8c70b375a02748b66906200012290839062000f5f565b6001600160a01b0382166000908152600a602052604090205460ff1615158115151415620002165760405162461bcd60e51b8152600401620000a39062000fc4565b6001600160a01b0382166000908152600a602052604090819020805460ff1916831515179055517f70af441dbb427737e6a5ef2cf5b664321011765ce1d19ce4a69cd024e69d4f2f906200026e908490849062000f73565b60405180910390a15050565b7f664d00954017f8b1153ec0813e86deff4b0eabd0548b1de8a6993f4549e0d42c624c4b40604051620002ae919062001000565b60405180910390a17fc93fa9fe410a29e605394838b98dd2b3b4b790b4f45b67dd8c0ddcdd149c4a746301312d00604051620002eb919062001000565b60405180910390a17f536bed877ca8a6a35942227bd9830bfa713b5822f6c5172a85fb51033975391c620f424060405162000327919062001000565b60405180910390a17f63e09f16584208fba1fc7ff64c62b00f07bec177c0d97ca6689891b1e77a35c761070860405162000362919062001000565b60405180910390a17fb7041340e0c2a075059bf0488a71c767724be15dae8e737f8460007325e8d85773d17b3c9784510e33cd5b87b490e79253bcd81e2e604051620003af919062000f5f565b60405180910390a1600080516020620053ba833981519152732fe16dd18bba26e457b7dd2080d5674312b026a26000604051620003ee92919062000f8e565b60405180910390a1600080516020620053ba83398151915273048f0e7ea2cfd522a4a058d1b1bdd574a0486c4660006040516200042d92919062000f8e565b60405180910390a1600080516020620053ba8339815191527337f6df71b40c50b2038329cabf5fda3682df1ebf60006040516200046c92919062000f8e565b60405180910390a1600080516020620053ba833981519152736ec472b613012a492693697fa551420e60567ea76000604051620004ab92919062000f8e565b60405180910390a1600080516020620053ba8339815191527343f0e5f2304f261dfa5359a0b74ff030e498d9046000604051620004ea92919062000f8e565b60405180910390a1600080516020620053ba83398151915273d66f214fb49f81ac5610e0339a351d7e1c67c35e60006040516200052992919062000f8e565b60405180910390a1600080516020620053ba83398151915273d4d2140ed70dcf8794a986f0cfd07560ee738c7160046040516200056892919062000f8e565b60405180910390a1600080516020620053ba8339815191527329b57d56a114ae5be3c129240898b3321a70a3006000604051620005a792919062000f8e565b60405180910390a1600080516020620053ba8339815191527361fa1cee13ceeaf20c30611c5e6da48c595f7db26000604051620005e692919062000f8e565b60405180910390a1600080516020620053ba83398151915273045950a37c59d75496bb4af68c05f9066a4c7e2760006040516200062592919062000f8e565b60405180910390a1600080516020620053ba83398151915273bee7ef1adfaa628536ebc0c1ebf082dbdc27265f60006040516200066492919062000f8e565b60405180910390a1600080516020620053ba8339815191527351badc1622c63d1e448a4f1ac1dc008b8a27fe676000604051620006a392919062000f8e565b60405180910390a1600080516020620053ba833981519152730e52db138df9ce54bc9d9330f418015ed512830a6000604051620006e292919062000f8e565b60405180910390a1600080516020620053ba83398151915273dde7684d88e0b482b2b455936fe0d22dd48cdcb360006040516200072192919062000f8e565b60405180910390a1600080516020620053ba8339815191527343102f07414d95ef71ec9aeba011b8595ba010d060006040516200076092919062000f8e565b60405180910390a16000805160206200539a83398151915260006127106040516200078d92919062000fab565b60405180910390a16000805160206200539a83398151915273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2617918604051620007cd92919062000fab565b60405180910390a16000805160206200539a83398151915273a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4861a4106040516200080d92919062000fab565b60405180910390a16000805160206200539a83398151915273dac17f958d2ee523a2206206994597c13d831ec7620101d06040516200084e92919062000fab565b60405180910390a16000805160206200539a833981519152732260fac5e5542a773aa44fbcfedf7c193bc2c5996184d06040516200088e92919062000fab565b60405180910390a16000805160206200539a833981519152734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b617918604051620008ce92919062000fab565b60405180910390a16000805160206200539a833981519152736b3595068778dd592e39a122f4f5a5cf09c90fe26179186040516200090e92919062000fab565b60405180910390a16000805160206200539a83398151915273ae7ab96520de3a18e5e111b5eaab095312d7fe84620109a06040516200094f92919062000fab565b60405180910390a16000805160206200539a833981519152737f39c581f595b53c5cb19bd0b3f8da6c935e2ca06179186040516200098f92919062000fab565b60405180910390a16000805160206200539a83398151915273d33526068d116ce69f19a9ee46f0bd304f21a51f617918604051620009cf92919062000fab565b60405180910390a16000805160206200539a8339815191527348c3399719b582dd63eb5aadf12a40b4c3f52fa2619c4060405162000a0f92919062000fab565b60405180910390a16000805160206200539a833981519152735a98fcbea516cf06857215779fd812ca3bef1b326202460860405162000a5092919062000fab565b60405180910390a16000805160206200539a833981519152739f8f72aa9304c8b593d555f12ef6589cc3a579a26184d060405162000a9092919062000fab565b60405180910390a16000805160206200539a833981519152731f9840a85d5af5bf1d1762f925bdaddc4201f98461908860405162000ad092919062000fab565b60405180910390a16000805160206200539a83398151915273514910771af9ca656af840dff83e8264ecf986ca617d0060405162000b1092919062000fab565b60405180910390a16000805160206200539a833981519152733c3a81e81dc49a522a592e7622a7e711c06bf3546184d060405162000b5092919062000fab565b60405180910390a16000805160206200537a83398151915273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2600160405162000b8f92919062000f73565b60405180910390a16000805160206200537a83398151915273a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48600160405162000bce92919062000f73565b60405180910390a16000805160206200537a83398151915273dac17f958d2ee523a2206206994597c13d831ec7600160405162000c0d92919062000f73565b60405180910390a16000805160206200537a833981519152732260fac5e5542a773aa44fbcfedf7c193bc2c599600160405162000c4c92919062000f73565b60405180910390a16000805160206200537a833981519152734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b600160405162000c8b92919062000f73565b60405180910390a16000805160206200537a833981519152736b3595068778dd592e39a122f4f5a5cf09c90fe2600160405162000cca92919062000f73565b60405180910390a16000805160206200537a83398151915273ae7ab96520de3a18e5e111b5eaab095312d7fe84600060405162000d0992919062000f73565b60405180910390a16000805160206200537a833981519152737f39c581f595b53c5cb19bd0b3f8da6c935e2ca0600160405162000d4892919062000f73565b60405180910390a16000805160206200537a83398151915273d33526068d116ce69f19a9ee46f0bd304f21a51f600160405162000d8792919062000f73565b60405180910390a16000805160206200537a8339815191527348c3399719b582dd63eb5aadf12a40b4c3f52fa2600160405162000dc692919062000f73565b60405180910390a16000805160206200537a833981519152735a98fcbea516cf06857215779fd812ca3bef1b32600160405162000e0592919062000f73565b60405180910390a16000805160206200537a833981519152739f8f72aa9304c8b593d555f12ef6589cc3a579a2600160405162000e4492919062000f73565b60405180910390a16000805160206200537a833981519152731f9840a85d5af5bf1d1762f925bdaddc4201f984600160405162000e8392919062000f73565b60405180910390a16000805160206200537a83398151915273514910771af9ca656af840dff83e8264ecf986ca600160405162000ec292919062000f73565b60405180910390a16000805160206200537a833981519152733c3a81e81dc49a522a592e7622a7e711c06bf354600160405162000f0192919062000f73565b60405180910390a1565b80516001600160a01b038116811462000f2357600080fd5b919050565b6000806040838503121562000f3b578182fd5b62000f468362000f0b565b915062000f566020840162000f0b565b90509250929050565b6001600160a01b0391909116815260200190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b0392909216825261ffff16602082015260400190565b6001600160a01b03929092168252602082015260400190565b6020808252600490820152635444303160e01b604082015260600190565b6020808252600490820152632a22181960e11b604082015260600190565b90815260200190565b61436180620010196000396000f3fe60806040526004361061026b5760003560e01c80638da5cb5b11610144578063ceb0981f116100b6578063e677e6c21161007a578063e677e6c214610686578063e6a0cc9414610699578063e88e0aab146106ae578063ee859d28146106c1578063ef381b33146106e1578063fe173b97146106f657610272565b8063ceb0981f146105f1578063d14533441461061e578063e30a49931461063e578063e5b1be6514610653578063e5e7988e1461066657610272565b8063b038555311610108578063b038555314610556578063ba4d531214610583578063bf6b874e14610596578063c45a0155146105b6578063c9cd9760146105cb578063cdfd7ca9146105de57610272565b80638da5cb5b146104db578063953556e2146104f05780639718f627146105035780639d08ebb514610523578063af482b581461053657610272565b80634d847865116101dd5780635e45da23116101a15780635e45da23146104545780636a42b8f8146104695780636de3c67c1461047e57806377632ec2146104935780637d7a7569146104b35780638406c079146104c657610272565b80634d847865146103cc5780635051349a146103ec57806356e56dcc1461040c578063576b332b1461042c57806357a62a4f1461043f57610272565b80633bbac5791161022f5780633bbac579146103315780633ed76f17146103515780633fc8cef31461036457806348d8d3881461037957806348f80c16146103995780634c016016146103ac57610272565b806313af40351461027757806320a68fab146102995780632c391c7b146102cf578063342aa8b5146102ef57806337b1b9581461030f57610272565b3661027257005b600080fd5b34801561028357600080fd5b50610297610292366004613518565b61070b565b005b3480156102a557600080fd5b506102b96102b4366004613518565b61074a565b6040516102c69190613ccf565b60405180910390f35b3480156102db57600080fd5b506102b96102ea366004613518565b61075e565b3480156102fb57600080fd5b5061029761030a36600461370b565b610769565b34801561031b57600080fd5b506103246107a1565b6040516102c69190613c00565b34801561033d57600080fd5b506102b961034c366004613518565b6107b0565b61029761035f3660046135c8565b6107c5565b34801561037057600080fd5b506103246107e5565b34801561038557600080fd5b50610324610394366004613550565b6107fd565b6102976103a736600461373f565b610892565b3480156103b857600080fd5b506102b96103c7366004613518565b610c4c565b3480156103d857600080fd5b506102976103e7366004613683565b610c58565b6103ff6103fa3660046137e4565b610cf8565b6040516102c69190614284565b34801561041857600080fd5b50610297610427366004613812565b610d9b565b6103ff61043a36600461394d565b610eda565b34801561044b57600080fd5b506103ff610f3d565b34801561046057600080fd5b506103ff610f44565b34801561047557600080fd5b506103ff610f4b565b34801561048a57600080fd5b506103ff610f51565b34801561049f57600080fd5b506102b96104ae36600461395f565b610f59565b6102976104c1366004613812565b610f6e565b3480156104d257600080fd5b506103246110c4565b3480156104e757600080fd5b506103246110dc565b6103ff6104fe3660046137e4565b6110eb565b34801561050f57600080fd5b506103ff61051e366004613518565b611182565b6103ff610531366004613800565b61118d565b34801561054257600080fd5b506102b9610551366004613518565b6111f3565b34801561056257600080fd5b50610576610571366004613518565b6111ff565b6040516102c69190614275565b6103ff6105913660046137e4565b611236565b3480156105a257600080fd5b506103ff6105b1366004613518565b61129c565b3480156105c257600080fd5b506103246112b7565b6102976105d9366004613588565b6112cf565b6102976105ec366004613812565b6112fe565b3480156105fd57600080fd5b5061061161060c36600461398f565b6114c8565b6040516102c69190613cff565b34801561062a57600080fd5b50610297610639366004613812565b6114de565b34801561064a57600080fd5b506103ff6115ab565b610297610661366004613633565b6115b1565b34801561067257600080fd5b506102b9610681366004613518565b6117bb565b610297610694366004613812565b6117c7565b3480156106a557600080fd5b506103ff611974565b6102976106bc366004613812565b61197a565b3480156106cd57600080fd5b506102976106dc366004613518565b611a84565b3480156106ed57600080fd5b50610324611ab7565b34801561070257600080fd5b506103ff611acf565b6008546001600160a01b0316331461073e5760405162461bcd60e51b815260040161073590613d8b565b60405180910390fd5b61074781611ad5565b50565b60006107568183611b7f565b90505b919050565b600061075682611bb3565b6008546001600160a01b031633146107935760405162461bcd60e51b815260040161073590613d8b565b61079d8282611e2b565b5050565b6009546001600160a01b031681565b600a6020526000908152604090205460ff1681565b6107d1858786846115b1565b6107dd838784846115b1565b505050505050565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290565b6009546000906001600160a01b0316331461082a5760405162461bcd60e51b815260040161073590613d8b565b6108348383611ecc565b5080915050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561087457600080fd5b505af1158015610888573d6000803e3d6000fd5b5050505092915050565b600b546001146108b45760405162461bcd60e51b815260040161073590613d13565b6002600b558060005a336000908152600a602052604081205491925090819060ff168061090b575060008052600a6020527f13da86008ba1c6922daee3e07db95305ef49ebced9f5467a0b8613fcc6b343e35460ff165b905060005b84811015610bc35760015487878381811061092757fe5b90506102800201600001351161093c57610bbb565b6004600088888481811061094c57fe5b61028002919091013582525060208101919091526040016000205460ff16156109955761099087878381811061097e57fe5b60009261028090910201359050611fa0565b610bbb565b73465e0b6518603e0d75b4737dac052845cf855925632e548b5b60008989858181106109bd57fe5b905061028002016040518363ffffffff1660e01b81526004016109e1929190613fdd565b60006040518083038186803b1580156109f957600080fd5b505af4158015610a0d573d6000803e3d6000fd5b505050506000878783818110610a1f57fe5b90506102800201606001359050428110610a395750610bc3565b8280610a4957506104b081014210155b610a655760405162461bcd60e51b815260040161073590613d8b565b6001935083888884818110610a7657fe5b905061028002016020016020810190610a8f91906137ca565b6004811115610a9a57fe5b1415610ac057610abb888884818110610aaf57fe5b90506102800201611fcc565b610bb9565b6002888884818110610ace57fe5b905061028002016020016020810190610ae791906137ca565b6004811115610af257fe5b1415610b1357610abb888884818110610b0757fe5b905061028002016121ad565b6003888884818110610b2157fe5b905061028002016020016020810190610b3a91906137ca565b6004811115610b4557fe5b1415610b6657610abb888884818110610b5a57fe5b905061028002016122dc565b6004888884818110610b7457fe5b905061028002016020016020810190610b8d91906137ca565b6004811115610b9857fe5b1415610bb957610bb9888884818110610bad57fe5b90506102800201612405565b505b600101610910565b508115610c3f5773465e0b6518603e0d75b4737dac052845cf855925639db74df16000610bf15a879061244c565b6040518363ffffffff1660e01b8152600401610c0e92919061409d565b60006040518083038186803b158015610c2657600080fd5b505af4158015610c3a573d6000803e3d6000fd5b505050505b50506001600b5550505050565b60006107568183612475565b6008546001600160a01b03163314610c825760405162461bcd60e51b815260040161073590613d8b565b604051638a6ade6360e01b815273465e0b6518603e0d75b4737dac052845cf85592590638a6ade6390610cc2906000908890889088908890600401613e5d565b60006040518083038186803b158015610cda57600080fd5b505af4158015610cee573d6000803e3d6000fd5b5050505050505050565b6000600b54600114610d1c5760405162461bcd60e51b815260040161073590613d13565b6002600b5560405162c44ff160e31b815273465e0b6518603e0d75b4737dac052845cf855925906306227f8890610d5d906000908690600790600401613ecf565b60006040518083038186803b158015610d7557600080fd5b505af4158015610d89573d6000803e3d6000fd5b50506000546001600b55949350505050565b600b54600114610dbd5760405162461bcd60e51b815260040161073590613d13565b6002600b55604051632e548b5b60e01b815273465e0b6518603e0d75b4737dac052845cf85592590632e548b5b90610dfc906000908590600401613fdd565b60006040518083038186803b158015610e1457600080fd5b505af4158015610e28573d6000803e3d6000fd5b5060029250610e35915050565b610e4660008335606085013561247e565b6005811115610e5157fe5b14610e6e5760405162461bcd60e51b815260040161073590613e03565b42610e8c62015180610e86606085013561070861244c565b9061250b565b10610ea95760405162461bcd60e51b815260040161073590613d31565b80356000908152600460205260409020805460ff19166001908117909155610ed290829061254c565b506001600b55565b6000600b54600114610efe5760405162461bcd60e51b815260040161073590613d13565b6002600b55604051636587992160e01b815273465e0b6518603e0d75b4737dac052845cf85592590636587992190610d5d906000908690600401613ff2565b620f424090565b624c4b4090565b61070890565b6301312d0090565b60009081526004602052604090205460ff1690565b333014610f8d5760405162461bcd60e51b815260040161073590613d8b565b6000610fbb610fa461018084016101608501613518565b610fb66101a085016101808601613518565b611ecc565b509050610fc66133e0565b610fd536849003840184613824565b81526001600160a01b0382166020820152610fef826111ff565b816040019061ffff16908161ffff1681525050816001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561103d57600080fd5b505af1158015611051573d6000803e3d6000fd5b50506040516383dc420b60e01b8152734a1dbc839b4ebad8db9058e856e90cb41dffce1f92506383dc420b915061108f9084906007906004016140d7565b60006040518083038186803b1580156110a757600080fd5b505af41580156110bb573d6000803e3d6000fd5b50505050505050565b73d17b3c9784510e33cd5b87b490e79253bcd81e2e90565b6008546001600160a01b031681565b6000600b5460011461110f5760405162461bcd60e51b815260040161073590613d13565b6002600b553373d17b3c9784510e33cd5b87b490e79253bcd81e2e146111475760405162461bcd60e51b815260040161073590613d8b565b604051621dd40d60e01b815273465e0b6518603e0d75b4737dac052845cf85592590621dd40d90610d5d906000908690600790600401613ecf565b60006107568261281e565b6000600b546001146111b15760405162461bcd60e51b815260040161073590613d13565b6002600b55604051638f0e6bef60e01b815273465e0b6518603e0d75b4737dac052845cf85592590638f0e6bef90610d5d906000908690600790600401613ef3565b60006107568183612af5565b600073d4d2140ed70dcf8794a986f0cfd07560ee738c716001600160a01b038316141561122e57506004610759565b506000919050565b6000600b5460011461125a5760405162461bcd60e51b815260040161073590613d13565b6002600b5560405163758e99b360e01b815273465e0b6518603e0d75b4737dac052845cf8559259063758e99b390610d5d906000908690600790600401613ecf565b6001600160a01b031660009081526007602052604090205490565b73c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c690565b3330146112ee5760405162461bcd60e51b815260040161073590613d8b565b6112f9838383612afe565b505050565b33301461131d5760405162461bcd60e51b815260040161073590613d8b565b6000611334610fa461018084016101608501613518565b509050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561137257600080fd5b505af1158015611386573d6000803e3d6000fd5b50506009546001600160a01b03169150638a34ffa290506113af61018085016101608601613518565b6113c16101a086016101808701613518565b846040518463ffffffff1660e01b81526004016113e093929190613c2e565b600060405180830381600087803b1580156113fa57600080fd5b505af115801561140e573d6000803e3d6000fd5b50505050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561144d57600080fd5b505af1158015611461573d6000803e3d6000fd5b5050604051636491033560e11b8152734a1dbc839b4ebad8db9058e856e90cb41dffce1f925063c922066a915061149c90859060040161422c565b60006040518083038186803b1580156114b457600080fd5b505af41580156107dd573d6000803e3d6000fd5b60006114d581848461247e565b90505b92915050565b600b546001146115005760405162461bcd60e51b815260040161073590613d13565b6002600b55604051632e548b5b60e01b815273465e0b6518603e0d75b4737dac052845cf85592590632e548b5b9061153f906000908590600401613fdd565b60006040518083038186803b15801561155757600080fd5b505af415801561156b573d6000803e3d6000fd5b505050813560009081526006602052604090205460ff1690506115a05760405162461bcd60e51b815260040161073590613d6d565b610ed281600061254c565b60005490565b3330146115d05760405162461bcd60e51b815260040161073590613d8b565b6001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21480156115f95750805b1561171757604051632a359a6d60e21b815260009073e92b1734fc37f8acc950d0d13a414753729587309063a8d669b490611641906007908990889087908b906004016140ab565b60206040518083038186803b15801561165957600080fd5b505af415801561166d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116919190613977565b604051632e1a7d4d60e01b815290915073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d906116cb908490600401614284565b600060405180830381600087803b1580156116e557600080fd5b505af11580156116f9573d6000803e3d6000fd5b50505050611711848261170c600061281e565b612c50565b506117b5565b604051632a359a6d60e21b81526117b5908590859073e92b1734fc37f8acc950d0d13a414753729587309063a8d669b4906117609060079086908a9060009088906004016140ab565b60206040518083038186803b15801561177857600080fd5b505af415801561178c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b09190613977565b612afe565b50505050565b60006107568183612ce2565b3330146117e65760405162461bcd60e51b815260040161073590613d8b565b60006117fd610fa461018084016101608501613518565b509050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561183b57600080fd5b505af115801561184f573d6000803e3d6000fd5b50506009546001600160a01b03169150638a34ffa2905061187861018085016101608601613518565b61188a6101a086016101808701613518565b846040518463ffffffff1660e01b81526004016118a993929190613c2e565b600060405180830381600087803b1580156118c357600080fd5b505af11580156118d7573d6000803e3d6000fd5b50505050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561191657600080fd5b505af115801561192a573d6000803e3d6000fd5b50505050734a1dbc839b4ebad8db9058e856e90cb41dffce1f632c9745af8383611953856111ff565b60076040518563ffffffff1660e01b815260040161149c949392919061423b565b60015490565b3330146119995760405162461bcd60e51b815260040161073590613d8b565b60006119b0610fa461018084016101608501613518565b5090506119bb6133e0565b6119ca36849003840184613824565b81526001600160a01b03821660208201526119e4826111ff565b816040019061ffff16908161ffff1681525050816001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a3257600080fd5b505af1158015611a46573d6000803e3d6000fd5b5050604051630287b3a760e31b8152734a1dbc839b4ebad8db9058e856e90cb41dffce1f925063143d9d38915061108f9084906007906004016140d7565b6008546001600160a01b03163314611aae5760405162461bcd60e51b815260040161073590613d8b565b61074781612ceb565b73d17b3c9784510e33cd5b87b490e79253bcd81e2e81565b60035490565b6008546001600160a01b0382811691161415611b035760405162461bcd60e51b815260040161073590613da9565b6001600160a01b038116611b295760405162461bcd60e51b815260040161073590613e3f565b600880546001600160a01b0319166001600160a01b0383161790556040517f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe290611b74908390613c00565b60405180910390a150565b600060025b6001600160a01b0383166000908152600585016020526040902054600160ff9283161b16161515905092915050565b600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0383161415611be257506001610759565b73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0383161415611c0f57506001610759565b73dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0383161415611c3c57506001610759565b732260fac5e5542a773aa44fbcfedf7c193bc2c5996001600160a01b0383161415611c6957506001610759565b734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b6001600160a01b0383161415611c9657506001610759565b736b3595068778dd592e39a122f4f5a5cf09c90fe26001600160a01b0383161415611cc357506001610759565b737f39c581f595b53c5cb19bd0b3f8da6c935e2ca06001600160a01b0383161415611cf057506001610759565b73d33526068d116ce69f19a9ee46f0bd304f21a51f6001600160a01b0383161415611d1d57506001610759565b7348c3399719b582dd63eb5aadf12a40b4c3f52fa26001600160a01b0383161415611d4a57506001610759565b735a98fcbea516cf06857215779fd812ca3bef1b326001600160a01b0383161415611d7757506001610759565b739f8f72aa9304c8b593d555f12ef6589cc3a579a26001600160a01b0383161415611da457506001610759565b731f9840a85d5af5bf1d1762f925bdaddc4201f9846001600160a01b0383161415611dd157506001610759565b73514910771af9ca656af840dff83e8264ecf986ca6001600160a01b0383161415611dfe57506001610759565b733c3a81e81dc49a522a592e7622a7e711c06bf3546001600160a01b038316141561122e57506001610759565b6001600160a01b0382166000908152600a602052604090205460ff1615158115151415611e6a5760405162461bcd60e51b815260040161073590613da9565b6001600160a01b0382166000908152600a602052604090819020805460ff1916831515179055517f70af441dbb427737e6a5ef2cf5b664321011765ce1d19ce4a69cd024e69d4f2f90611ec09084908490613cb4565b60405180910390a15050565b60405163e6a4390560e01b8152600090819073c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c69063e6a4390590611f0a9087908790600401613c14565b60206040518083038186803b158015611f2257600080fd5b505afa158015611f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5a9190613534565b91506001600160a01b038216611f825760405162461bcd60e51b815260040161073590613de5565b826001600160a01b0316846001600160a01b03161190509250929050565b6001808301805490910190819055811461079d5760405162461bcd60e51b815260040161073590613e21565b60005a9050611fdd60008335611fa0565b60008030612024611ffe611ff96101a088016101808901613518565b61281e565b612013611ff961018089016101608a01613518565b60c088013591016201a51c0161244c565b60405163733bf36160e11b9061203e90889060240161422c565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161207c9190613be4565b60006040518083038160008787f1925050503d80600081146120ba576040519150601f19603f3d011682016040523d82523d6000602084013e6120bf565b606091505b50909250905060018261212b576121286120e16101c087016101a08801613518565b6120f361018088016101608901613518565b61012088013561210b6101a08a016101808b01613518565b6101408a013561212160a08c0160808d016137b0565b6000612d8a565b90505b61213481612ee5565b60008061215c60c088013560e0890135886121576101c08c016101a08d01613518565b612f03565b915091508415156000600101547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c386858560405161219c93929190613cda565b60405180910390a350505050505050565b60005a90506121be60008335611fa0565b600080306121d360c08601356201dfb461244c565b60405163cdfd7ca960e01b906121ed90889060240161422c565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161222b9190613be4565b60006040518083038160008787f1925050503d8060008114612269576040519150601f19603f3d011682016040523d82523d6000602084013e61226e565b606091505b50909250905060018261212b5760006122a461229261018088016101608901613518565b610fb66101a089016101808a01613518565b5090506122d0816122bd6101c089016101a08a01613518565b61010089013563064e6cbb60e51b612f93565b91505061213481612ee5565b60005a90506122ed60008335611fa0565b60008030612319612309611ff961018088016101608901613518565b60c087013590620156fc0161244c565b60405163e88e0aab60e01b9061233390889060240161422c565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516123719190613be4565b60006040518083038160008787f1925050503d80600081146123af576040519150601f19603f3d011682016040523d82523d6000602084013e6123b4565b606091505b50909250905060018261212b576121286123d661018087016101608801613518565b6123e86101c088016101a08901613518565b6101208801356123fe60a08a0160808b016137b0565b600061309e565b60005a905061241660008335611fa0565b60008030612432612309611ff961018088016101608901613518565b604051637d7a756960e01b9061233390889060240161422c565b60006114d583836040518060400160405280600481526020016329a6989960e11b8152506131be565b60006003611b84565b825460009083111561249257506000612504565b600083815260048501602052604090205460ff16156124b357506005612504565b600083815260068501602052604090205460ff16156124d457506004612504565b60008381526002850160205260409020546124f157506003612504565b42821061250057506001612504565b5060025b9392505050565b808201828110156114d8576040805162461bcd60e51b81526020600480830191909152602482015263534d344560e01b604482015290519081900360640190fd5b60004261256160608501356301e1338061250b565b109050600161257660408501602086016137ca565b600481111561258157fe5b141561265e576000816125a5576125a06101c085016101a08601613518565b6125b2565b6008546001600160a01b03165b90506125ff816125ca61018087016101608801613518565b6101208701356125e26101a089016101808a01613518565b6101408901356125f860a08b0160808c016137b0565b6001612d8a565b61261b5760405162461bcd60e51b815260040161073590613d4f565b82156126585761263c8161263760e087013560c0880135613256565b6132ab565b6126585760405162461bcd60e51b815260040161073590613dc7565b50612812565b600261267060408501602086016137ca565b600481111561267b57fe5b141561274d5760006126aa61269861018086016101608701613518565b610fb66101a087016101808801613518565b5090506000826126cb576126c66101c086016101a08701613518565b6126d8565b6008546001600160a01b03165b90506126f2828261010088013563064e6cbb60e51b612f93565b61270e5760405162461bcd60e51b815260040161073590613d4f565b83156127465761272a8161263760e088013560c0890135613256565b6127465760405162461bcd60e51b815260040161073590613dc7565b5050612812565b600361275f60408501602086016137ca565b600481111561276a57fe5b14156127d05760008161278e576127896101c085016101a08601613518565b61279b565b6008546001600160a01b03165b90506125ff6127b261018086016101608701613518565b826101208701356127c960a0890160808a016137b0565b600161309e565b60046127e260408501602086016137ca565b60048111156127ed57fe5b141561280c5760008161278e576127896101c085016101a08601613518565b5061079d565b6112f96000843561331a565b60006001600160a01b0382166128375750612710610759565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03831614156128655750617918610759565b73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0383161415612893575061a410610759565b73dac17f958d2ee523a2206206994597c13d831ec76001600160a01b03831614156128c25750620101d0610759565b732260fac5e5542a773aa44fbcfedf7c193bc2c5996001600160a01b03831614156128f057506184d0610759565b734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b6001600160a01b038316141561291e5750617918610759565b736b3595068778dd592e39a122f4f5a5cf09c90fe26001600160a01b038316141561294c5750617918610759565b73ae7ab96520de3a18e5e111b5eaab095312d7fe846001600160a01b038316141561297b5750620109a0610759565b737f39c581f595b53c5cb19bd0b3f8da6c935e2ca06001600160a01b03831614156129a95750617918610759565b73d33526068d116ce69f19a9ee46f0bd304f21a51f6001600160a01b03831614156129d75750617918610759565b7348c3399719b582dd63eb5aadf12a40b4c3f52fa26001600160a01b0383161415612a055750619c40610759565b735a98fcbea516cf06857215779fd812ca3bef1b326001600160a01b0383161415612a34575062024608610759565b739f8f72aa9304c8b593d555f12ef6589cc3a579a26001600160a01b0383161415612a6257506184d0610759565b731f9840a85d5af5bf1d1762f925bdaddc4201f9846001600160a01b0383161415612a905750619088610759565b73514910771af9ca656af840dff83e8264ecf986ca6001600160a01b0383161415612abe5750617d00610759565b733c3a81e81dc49a522a592e7622a7e711c06bf3546001600160a01b0383161415612aec57506184d0610759565b5061ea60919050565b60006001611b84565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b60208310612b7a5780518252601f199092019160209182019101612b5b565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612bdc576040519150601f19603f3d011682016040523d82523d6000602084013e612be1565b606091505b5091509150818015612c0f575080511580612c0f5750808060200190516020811015612c0c57600080fd5b50515b612c49576040805162461bcd60e51b815260206004808301919091526024820152635448303560e01b604482015290519081900360640190fd5b5050505050565b6040516000906001600160a01b038516908390859084818181858888f193505050503d8060008114612c9e576040519150601f19603f3d011682016040523d82523d6000602084013e612ca3565b606091505b50509050806117b5576040805162461bcd60e51b815260206004808301919091526024820152632a2419a360e11b604482015290519081900360640190fd5b60006004611b84565b6009546001600160a01b0382811691161415612d195760405162461bcd60e51b815260040161073590613da9565b6001600160a01b038116612d3f5760405162461bcd60e51b815260040161073590613e3f565b600980546001600160a01b0319166001600160a01b0383161790556040517f99db624faf5b574db8409c17138c4894a18b552e2cd1dbe8c70b375a02748b6690611b74908390613c00565b600080803084612db057612d9d8861281e565b612da68b61281e565b01619c4001612db2565b5a5b604051633ed76f1760e01b90612dd6908e908e908e908e908e908e90602401613c51565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612e149190613be4565b60006040518083038160008787f1925050503d8060008114612e52576040519150601f19603f3d011682016040523d82523d6000602084013e612e57565b606091505b509150915081612ed857886001600160a01b03168a6001600160a01b031660008051602061430c8339815191528a84604051612e9492919061428d565b60405180910390a3866001600160a01b03168a6001600160a01b031660008051602061430c8339815191528884604051612ecf92919061428d565b60405180910390a35b5098975050505050505050565b80612ef957612ef4600061332e565b610747565b6107476000613353565b60008080612f118787613256565b9050612f246193ac610e865a889061244c565b92506000612f4982612f446000600301548761325690919063ffffffff16565b61336c565b9050612f55828261244c565b9250612f6133826132ab565b612f7d5760405162461bcd60e51b815260040161073590613dc7565b612f8785846132ab565b50505094509492505050565b600082612fa257506001613096565b600080306001600160a01b031661d6d8858989896000604051602401612fcb9493929190613c8b565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516130099190613be4565b60006040518083038160008787f1925050503d8060008114613047576040519150601f19603f3d011682016040523d82523d6000602084013e61304c565b606091505b50915091508161309257866001600160a01b0316866001600160a01b031660008051602061430c833981519152878460405161308992919061428d565b60405180910390a35b5090505b949350505050565b6000836130ad575060016131b5565b60008030846130c8576130bf8961281e565b614e20016130ca565b5a5b60405163e5b1be6560e01b906130ea908c908c908c908c90602401613c8b565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516131289190613be4565b60006040518083038160008787f1925050503d8060008114613166576040519150601f19603f3d011682016040523d82523d6000602084013e61316b565b606091505b5091509150816131b157876001600160a01b0316876001600160a01b031660008051602061430c83398151915288846040516131a892919061428d565b60405180910390a35b5090505b95945050505050565b818303818482111561324e5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156132135781810151838201526020016131fb565b50505050905090810190601f1680156132405780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509392505050565b60008115806132715750508082028282828161326e57fe5b04145b6114d8576040805162461bcd60e51b81526020600480830191909152602482015263534d324160e01b604482015290519081900360640190fd5b6000816132ba575060016114d8565b6132ce83836132c9600061281e565b613382565b9050801515836001600160a01b03167fdbef2fc26e7694e7a1c5a4801b1ad144136d149cf76f310a780689b4087f0ffe8460405161330c9190614284565b60405180910390a392915050565b600090815260029091016020526040812055565b600181810154600090815260069092016020526040909120805460ff19169091179055565b6001810154600090815260029091016020526040812055565b600081831061337b57816114d5565b5090919050565b6040516000906001600160a01b038516908390859084818181858888f193505050503d80600081146133d0576040519150601f19603f3d011682016040523d82523d6000602084013e6133d5565b606091505b509095945050505050565b60405180606001604052806133f3613407565b815260006020820181905260409091015290565b6040805161028081019091526000808252602082019081526020016000151581526020016000815260200160001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000151581526020016000815260200160008152602001600081525090565b8035610759816142f6565b8035801515811461075957600080fd5b80356005811061075957600080fd5b600061010082840312156134fe578081fd5b50919050565b803563ffffffff8116811461075957600080fd5b600060208284031215613529578081fd5b8135612504816142f6565b600060208284031215613545578081fd5b8151612504816142f6565b60008060408385031215613562578081fd5b823561356d816142f6565b9150602083013561357d816142f6565b809150509250929050565b60008060006060848603121561359c578081fd5b83356135a7816142f6565b925060208401356135b7816142f6565b929592945050506040919091013590565b60008060008060008060c087890312156135e0578182fd5b86356135eb816142f6565b955060208701356135fb816142f6565b9450604087013593506060870135613612816142f6565b92506080870135915061362760a088016134cd565b90509295509295509295565b60008060008060808587031215613648578384fd5b8435613653816142f6565b93506020850135613663816142f6565b925060408501359150613678606086016134cd565b905092959194509250565b60008060008060608587031215613698578182fd5b84356136a3816142f6565b9350602085013567ffffffffffffffff808211156136bf578384fd5b818701915087601f8301126136d2578384fd5b8135818111156136e0578485fd5b88602080830285010111156136f3578485fd5b602083019550809450505050613678604086016134cd565b6000806040838503121561371d578182fd5b8235613728816142f6565b9150613736602084016134cd565b90509250929050565b60008060208385031215613751578182fd5b823567ffffffffffffffff80821115613768578384fd5b818501915085601f83011261377b578384fd5b813581811115613789578485fd5b8660206102808302850101111561379e578485fd5b60209290920196919550909350505050565b6000602082840312156137c1578081fd5b6114d5826134cd565b6000602082840312156137db578081fd5b6114d5826134dd565b600061010082840312156137f6578081fd5b6114d583836134ec565b600061016082840312156134fe578081fd5b600061028082840312156134fe578081fd5b6000610280808385031215613837578182fd5b613840816142a6565b905082358152613852602084016134dd565b6020820152613863604084016134cd565b60408201526060830135606082015261387e608084016134cd565b608082015260a083013560a082015260c083013560c082015260e083013560e08201526101008084013581830152506101208084013581830152506101408084013581830152506101606138d38185016134c2565b908201526101806138e58482016134c2565b908201526101a06138f78482016134c2565b908201526101c083810135908201526101e0808401359082015261020061391f8185016134cd565b9082015261022083810135908201526102408084013590820152610260928301359281019290925250919050565b600061012082840312156134fe578081fd5b600060208284031215613970578081fd5b5035919050565b600060208284031215613988578081fd5b5051919050565b600080604083850312156139a1578182fd5b50508035926020909101359150565b6001600160a01b03169052565b15159052565b600081518084526139db8160208601602086016142ca565b601f01601f19169290920160200192915050565b600581106139f957fe5b9052565b8035613a08816142f6565b6001600160a01b039081168352602082013590613a24826142f6565b80821660208501526040830135604085015260608301356060850152613a4c608084016134cd565b1515608085015260a08301359150613a63826142f6565b1660a083015260c08181013590830152613a7f60e08201613504565b6112f960e0840182613bda565b80358252613a9c602082016134dd565b613aa960208401826139ef565b50613ab6604082016134cd565b613ac360408401826139bd565b5060608101356060830152613ada608082016134cd565b613ae760808401826139bd565b5060a081013560a083015260c081013560c083015260e081013560e0830152610100808201358184015250610120808201358184015250610140808201358184015250610160613b388183016134c2565b613b44828501826139b0565b5050610180613b548183016134c2565b613b60828501826139b0565b50506101a0613b708183016134c2565b613b7c828501826139b0565b50506101c081810135908301526101e08082013590830152610200613ba28183016134cd565b613bae828501826139bd565b50506102208181013590830152610240808201359083015261026090810135910152565b61ffff169052565b63ffffffff169052565b60008251613bf68184602087016142ca565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b0396871681529486166020860152604085019390935293166060830152608082019290925290151560a082015260c00190565b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b6001600160a01b039290921682521515602082015260400190565b901515815260200190565b600060608252613ced60608301866139c3565b60208301949094525060400152919050565b6020810160068310613d0d57fe5b91905290565b6020808252600490820152632a22181b60e11b604082015260600190565b6020808252600490820152635444314360e01b604082015260600190565b60208082526004908201526315110c4d60e21b604082015260600190565b6020808252600490820152635444323160e01b604082015260600190565b6020808252600490820152630544430360e41b604082015260600190565b6020808252600490820152635444303160e01b604082015260600190565b6020808252600490820152630544434360e41b604082015260600190565b6020808252600490820152634f53313760e01b604082015260600190565b6020808252600490820152632a221a9960e11b604082015260600190565b60208082526004908201526327a99b9960e11b604082015260600190565b6020808252600490820152632a22181960e11b604082015260600190565b8581526001600160a01b0385166020808301919091526080604083018190528201849052600090859060a08401835b87811015613eb657613ea682613ea1866134dd565b6139ef565b9282019290820190600101613e8c565b5080935050505082151560608301529695505050505050565b8381526101408101613ee460208301856139fd565b82610120830152949350505050565b8381526101a08101613f1060208301613f0b866134c2565b6139b0565b613f1c602085016134c2565b613f2960408401826139b0565b506040840135606083015260608401356080830152608084013560a083015260a084013560c0830152613f5e60c085016134cd565b613f6b60e08401826139bd565b50613f7860e085016134cd565b610100613f87818501836139bd565b613f928187016134c2565b915050610120613fa4818501836139b0565b6101409150808601358285015250613fbd818601613504565b9050613fcd610160840182613bda565b5082610180830152949350505050565b8281526102a081016125046020830184613a8c565b828152610140810161400a60208301613f0b856134c2565b614016602084016134c2565b61402360408401826139b0565b506040830135606083015260608301356080830152608083013560a083015261404e60a084016134cd565b61405b60c08401826139bd565b5061406860c084016134c2565b61407560e08401826139b0565b5061010060e08401358184015261408d818501613504565b905061324e610120840182613bda565b918252602082015260400190565b9485526001600160a01b0393841660208601526040850192909252606084015216608082015260a00190565b60006102e08201905083518051835260208101516140f860208501826139ef565b50604081015161410b60408501826139bd565b5060608101516060840152608081015161412860808501826139bd565b5060a081015160a084015260c081015160c084015260e081015160e08401526101008082015181850152506101208082015181850152506101408082015181850152506101608082015161417e828601826139b0565b505061018080820151614193828601826139b0565b50506101a0808201516141a8828601826139b0565b50506101c081810151908401526101e08082015190840152610200808201516141d3828601826139bd565b505061022081810151908401526102408082015190840152610260908101519083015260208401516142096102808401826139b0565b50604084015161421d6102a0840182613bd2565b50826102c08301529392505050565b61028081016114d88284613a8c565b6102e0810161424a8287613a8c565b6001600160a01b039490941661028082015261ffff929092166102a08301526102c090910152919050565b61ffff91909116815260200190565b90815260200190565b60008382526040602083015261309660408301846139c3565b60405181810167ffffffffffffffff811182821017156142c257fe5b604052919050565b60005b838110156142e55781810151838201526020016142cd565b838111156117b55750506000910152565b6001600160a01b038116811461074757600080fdfe786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b211592a264697066735822122099bde760c5a3a45475e145709e72c67d165673645fd1abfea9ffbe368107fd4764736f6c63430007060033ed243800dd924a6f05da349ad56411a9154d39d02c09c49db8faafc3966306968563e1de6a8955dcbdc3719833791025efb62c4cb350b8a64bc6823168115f026b4044e33be5af8fcdb7449c49137010eede3c8c06d5d08067151a7ace17266d000000000000000000000000f4418d9fe76a788f2868a558dd216549ad2d869b0000000000000000000000003a1d749fa4a9e650fce844ff1c58c5faf7e2a9d1

Deployed Bytecode

0x60806040526004361061026b5760003560e01c80638da5cb5b11610144578063ceb0981f116100b6578063e677e6c21161007a578063e677e6c214610686578063e6a0cc9414610699578063e88e0aab146106ae578063ee859d28146106c1578063ef381b33146106e1578063fe173b97146106f657610272565b8063ceb0981f146105f1578063d14533441461061e578063e30a49931461063e578063e5b1be6514610653578063e5e7988e1461066657610272565b8063b038555311610108578063b038555314610556578063ba4d531214610583578063bf6b874e14610596578063c45a0155146105b6578063c9cd9760146105cb578063cdfd7ca9146105de57610272565b80638da5cb5b146104db578063953556e2146104f05780639718f627146105035780639d08ebb514610523578063af482b581461053657610272565b80634d847865116101dd5780635e45da23116101a15780635e45da23146104545780636a42b8f8146104695780636de3c67c1461047e57806377632ec2146104935780637d7a7569146104b35780638406c079146104c657610272565b80634d847865146103cc5780635051349a146103ec57806356e56dcc1461040c578063576b332b1461042c57806357a62a4f1461043f57610272565b80633bbac5791161022f5780633bbac579146103315780633ed76f17146103515780633fc8cef31461036457806348d8d3881461037957806348f80c16146103995780634c016016146103ac57610272565b806313af40351461027757806320a68fab146102995780632c391c7b146102cf578063342aa8b5146102ef57806337b1b9581461030f57610272565b3661027257005b600080fd5b34801561028357600080fd5b50610297610292366004613518565b61070b565b005b3480156102a557600080fd5b506102b96102b4366004613518565b61074a565b6040516102c69190613ccf565b60405180910390f35b3480156102db57600080fd5b506102b96102ea366004613518565b61075e565b3480156102fb57600080fd5b5061029761030a36600461370b565b610769565b34801561031b57600080fd5b506103246107a1565b6040516102c69190613c00565b34801561033d57600080fd5b506102b961034c366004613518565b6107b0565b61029761035f3660046135c8565b6107c5565b34801561037057600080fd5b506103246107e5565b34801561038557600080fd5b50610324610394366004613550565b6107fd565b6102976103a736600461373f565b610892565b3480156103b857600080fd5b506102b96103c7366004613518565b610c4c565b3480156103d857600080fd5b506102976103e7366004613683565b610c58565b6103ff6103fa3660046137e4565b610cf8565b6040516102c69190614284565b34801561041857600080fd5b50610297610427366004613812565b610d9b565b6103ff61043a36600461394d565b610eda565b34801561044b57600080fd5b506103ff610f3d565b34801561046057600080fd5b506103ff610f44565b34801561047557600080fd5b506103ff610f4b565b34801561048a57600080fd5b506103ff610f51565b34801561049f57600080fd5b506102b96104ae36600461395f565b610f59565b6102976104c1366004613812565b610f6e565b3480156104d257600080fd5b506103246110c4565b3480156104e757600080fd5b506103246110dc565b6103ff6104fe3660046137e4565b6110eb565b34801561050f57600080fd5b506103ff61051e366004613518565b611182565b6103ff610531366004613800565b61118d565b34801561054257600080fd5b506102b9610551366004613518565b6111f3565b34801561056257600080fd5b50610576610571366004613518565b6111ff565b6040516102c69190614275565b6103ff6105913660046137e4565b611236565b3480156105a257600080fd5b506103ff6105b1366004613518565b61129c565b3480156105c257600080fd5b506103246112b7565b6102976105d9366004613588565b6112cf565b6102976105ec366004613812565b6112fe565b3480156105fd57600080fd5b5061061161060c36600461398f565b6114c8565b6040516102c69190613cff565b34801561062a57600080fd5b50610297610639366004613812565b6114de565b34801561064a57600080fd5b506103ff6115ab565b610297610661366004613633565b6115b1565b34801561067257600080fd5b506102b9610681366004613518565b6117bb565b610297610694366004613812565b6117c7565b3480156106a557600080fd5b506103ff611974565b6102976106bc366004613812565b61197a565b3480156106cd57600080fd5b506102976106dc366004613518565b611a84565b3480156106ed57600080fd5b50610324611ab7565b34801561070257600080fd5b506103ff611acf565b6008546001600160a01b0316331461073e5760405162461bcd60e51b815260040161073590613d8b565b60405180910390fd5b61074781611ad5565b50565b60006107568183611b7f565b90505b919050565b600061075682611bb3565b6008546001600160a01b031633146107935760405162461bcd60e51b815260040161073590613d8b565b61079d8282611e2b565b5050565b6009546001600160a01b031681565b600a6020526000908152604090205460ff1681565b6107d1858786846115b1565b6107dd838784846115b1565b505050505050565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290565b6009546000906001600160a01b0316331461082a5760405162461bcd60e51b815260040161073590613d8b565b6108348383611ecc565b5080915050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561087457600080fd5b505af1158015610888573d6000803e3d6000fd5b5050505092915050565b600b546001146108b45760405162461bcd60e51b815260040161073590613d13565b6002600b558060005a336000908152600a602052604081205491925090819060ff168061090b575060008052600a6020527f13da86008ba1c6922daee3e07db95305ef49ebced9f5467a0b8613fcc6b343e35460ff165b905060005b84811015610bc35760015487878381811061092757fe5b90506102800201600001351161093c57610bbb565b6004600088888481811061094c57fe5b61028002919091013582525060208101919091526040016000205460ff16156109955761099087878381811061097e57fe5b60009261028090910201359050611fa0565b610bbb565b73465e0b6518603e0d75b4737dac052845cf855925632e548b5b60008989858181106109bd57fe5b905061028002016040518363ffffffff1660e01b81526004016109e1929190613fdd565b60006040518083038186803b1580156109f957600080fd5b505af4158015610a0d573d6000803e3d6000fd5b505050506000878783818110610a1f57fe5b90506102800201606001359050428110610a395750610bc3565b8280610a4957506104b081014210155b610a655760405162461bcd60e51b815260040161073590613d8b565b6001935083888884818110610a7657fe5b905061028002016020016020810190610a8f91906137ca565b6004811115610a9a57fe5b1415610ac057610abb888884818110610aaf57fe5b90506102800201611fcc565b610bb9565b6002888884818110610ace57fe5b905061028002016020016020810190610ae791906137ca565b6004811115610af257fe5b1415610b1357610abb888884818110610b0757fe5b905061028002016121ad565b6003888884818110610b2157fe5b905061028002016020016020810190610b3a91906137ca565b6004811115610b4557fe5b1415610b6657610abb888884818110610b5a57fe5b905061028002016122dc565b6004888884818110610b7457fe5b905061028002016020016020810190610b8d91906137ca565b6004811115610b9857fe5b1415610bb957610bb9888884818110610bad57fe5b90506102800201612405565b505b600101610910565b508115610c3f5773465e0b6518603e0d75b4737dac052845cf855925639db74df16000610bf15a879061244c565b6040518363ffffffff1660e01b8152600401610c0e92919061409d565b60006040518083038186803b158015610c2657600080fd5b505af4158015610c3a573d6000803e3d6000fd5b505050505b50506001600b5550505050565b60006107568183612475565b6008546001600160a01b03163314610c825760405162461bcd60e51b815260040161073590613d8b565b604051638a6ade6360e01b815273465e0b6518603e0d75b4737dac052845cf85592590638a6ade6390610cc2906000908890889088908890600401613e5d565b60006040518083038186803b158015610cda57600080fd5b505af4158015610cee573d6000803e3d6000fd5b5050505050505050565b6000600b54600114610d1c5760405162461bcd60e51b815260040161073590613d13565b6002600b5560405162c44ff160e31b815273465e0b6518603e0d75b4737dac052845cf855925906306227f8890610d5d906000908690600790600401613ecf565b60006040518083038186803b158015610d7557600080fd5b505af4158015610d89573d6000803e3d6000fd5b50506000546001600b55949350505050565b600b54600114610dbd5760405162461bcd60e51b815260040161073590613d13565b6002600b55604051632e548b5b60e01b815273465e0b6518603e0d75b4737dac052845cf85592590632e548b5b90610dfc906000908590600401613fdd565b60006040518083038186803b158015610e1457600080fd5b505af4158015610e28573d6000803e3d6000fd5b5060029250610e35915050565b610e4660008335606085013561247e565b6005811115610e5157fe5b14610e6e5760405162461bcd60e51b815260040161073590613e03565b42610e8c62015180610e86606085013561070861244c565b9061250b565b10610ea95760405162461bcd60e51b815260040161073590613d31565b80356000908152600460205260409020805460ff19166001908117909155610ed290829061254c565b506001600b55565b6000600b54600114610efe5760405162461bcd60e51b815260040161073590613d13565b6002600b55604051636587992160e01b815273465e0b6518603e0d75b4737dac052845cf85592590636587992190610d5d906000908690600401613ff2565b620f424090565b624c4b4090565b61070890565b6301312d0090565b60009081526004602052604090205460ff1690565b333014610f8d5760405162461bcd60e51b815260040161073590613d8b565b6000610fbb610fa461018084016101608501613518565b610fb66101a085016101808601613518565b611ecc565b509050610fc66133e0565b610fd536849003840184613824565b81526001600160a01b0382166020820152610fef826111ff565b816040019061ffff16908161ffff1681525050816001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561103d57600080fd5b505af1158015611051573d6000803e3d6000fd5b50506040516383dc420b60e01b8152734a1dbc839b4ebad8db9058e856e90cb41dffce1f92506383dc420b915061108f9084906007906004016140d7565b60006040518083038186803b1580156110a757600080fd5b505af41580156110bb573d6000803e3d6000fd5b50505050505050565b73d17b3c9784510e33cd5b87b490e79253bcd81e2e90565b6008546001600160a01b031681565b6000600b5460011461110f5760405162461bcd60e51b815260040161073590613d13565b6002600b553373d17b3c9784510e33cd5b87b490e79253bcd81e2e146111475760405162461bcd60e51b815260040161073590613d8b565b604051621dd40d60e01b815273465e0b6518603e0d75b4737dac052845cf85592590621dd40d90610d5d906000908690600790600401613ecf565b60006107568261281e565b6000600b546001146111b15760405162461bcd60e51b815260040161073590613d13565b6002600b55604051638f0e6bef60e01b815273465e0b6518603e0d75b4737dac052845cf85592590638f0e6bef90610d5d906000908690600790600401613ef3565b60006107568183612af5565b600073d4d2140ed70dcf8794a986f0cfd07560ee738c716001600160a01b038316141561122e57506004610759565b506000919050565b6000600b5460011461125a5760405162461bcd60e51b815260040161073590613d13565b6002600b5560405163758e99b360e01b815273465e0b6518603e0d75b4737dac052845cf8559259063758e99b390610d5d906000908690600790600401613ecf565b6001600160a01b031660009081526007602052604090205490565b73c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c690565b3330146112ee5760405162461bcd60e51b815260040161073590613d8b565b6112f9838383612afe565b505050565b33301461131d5760405162461bcd60e51b815260040161073590613d8b565b6000611334610fa461018084016101608501613518565b509050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561137257600080fd5b505af1158015611386573d6000803e3d6000fd5b50506009546001600160a01b03169150638a34ffa290506113af61018085016101608601613518565b6113c16101a086016101808701613518565b846040518463ffffffff1660e01b81526004016113e093929190613c2e565b600060405180830381600087803b1580156113fa57600080fd5b505af115801561140e573d6000803e3d6000fd5b50505050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561144d57600080fd5b505af1158015611461573d6000803e3d6000fd5b5050604051636491033560e11b8152734a1dbc839b4ebad8db9058e856e90cb41dffce1f925063c922066a915061149c90859060040161422c565b60006040518083038186803b1580156114b457600080fd5b505af41580156107dd573d6000803e3d6000fd5b60006114d581848461247e565b90505b92915050565b600b546001146115005760405162461bcd60e51b815260040161073590613d13565b6002600b55604051632e548b5b60e01b815273465e0b6518603e0d75b4737dac052845cf85592590632e548b5b9061153f906000908590600401613fdd565b60006040518083038186803b15801561155757600080fd5b505af415801561156b573d6000803e3d6000fd5b505050813560009081526006602052604090205460ff1690506115a05760405162461bcd60e51b815260040161073590613d6d565b610ed281600061254c565b60005490565b3330146115d05760405162461bcd60e51b815260040161073590613d8b565b6001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21480156115f95750805b1561171757604051632a359a6d60e21b815260009073e92b1734fc37f8acc950d0d13a414753729587309063a8d669b490611641906007908990889087908b906004016140ab565b60206040518083038186803b15801561165957600080fd5b505af415801561166d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116919190613977565b604051632e1a7d4d60e01b815290915073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d906116cb908490600401614284565b600060405180830381600087803b1580156116e557600080fd5b505af11580156116f9573d6000803e3d6000fd5b50505050611711848261170c600061281e565b612c50565b506117b5565b604051632a359a6d60e21b81526117b5908590859073e92b1734fc37f8acc950d0d13a414753729587309063a8d669b4906117609060079086908a9060009088906004016140ab565b60206040518083038186803b15801561177857600080fd5b505af415801561178c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b09190613977565b612afe565b50505050565b60006107568183612ce2565b3330146117e65760405162461bcd60e51b815260040161073590613d8b565b60006117fd610fa461018084016101608501613518565b509050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561183b57600080fd5b505af115801561184f573d6000803e3d6000fd5b50506009546001600160a01b03169150638a34ffa2905061187861018085016101608601613518565b61188a6101a086016101808701613518565b846040518463ffffffff1660e01b81526004016118a993929190613c2e565b600060405180830381600087803b1580156118c357600080fd5b505af11580156118d7573d6000803e3d6000fd5b50505050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561191657600080fd5b505af115801561192a573d6000803e3d6000fd5b50505050734a1dbc839b4ebad8db9058e856e90cb41dffce1f632c9745af8383611953856111ff565b60076040518563ffffffff1660e01b815260040161149c949392919061423b565b60015490565b3330146119995760405162461bcd60e51b815260040161073590613d8b565b60006119b0610fa461018084016101608501613518565b5090506119bb6133e0565b6119ca36849003840184613824565b81526001600160a01b03821660208201526119e4826111ff565b816040019061ffff16908161ffff1681525050816001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a3257600080fd5b505af1158015611a46573d6000803e3d6000fd5b5050604051630287b3a760e31b8152734a1dbc839b4ebad8db9058e856e90cb41dffce1f925063143d9d38915061108f9084906007906004016140d7565b6008546001600160a01b03163314611aae5760405162461bcd60e51b815260040161073590613d8b565b61074781612ceb565b73d17b3c9784510e33cd5b87b490e79253bcd81e2e81565b60035490565b6008546001600160a01b0382811691161415611b035760405162461bcd60e51b815260040161073590613da9565b6001600160a01b038116611b295760405162461bcd60e51b815260040161073590613e3f565b600880546001600160a01b0319166001600160a01b0383161790556040517f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe290611b74908390613c00565b60405180910390a150565b600060025b6001600160a01b0383166000908152600585016020526040902054600160ff9283161b16161515905092915050565b600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0383161415611be257506001610759565b73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0383161415611c0f57506001610759565b73dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0383161415611c3c57506001610759565b732260fac5e5542a773aa44fbcfedf7c193bc2c5996001600160a01b0383161415611c6957506001610759565b734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b6001600160a01b0383161415611c9657506001610759565b736b3595068778dd592e39a122f4f5a5cf09c90fe26001600160a01b0383161415611cc357506001610759565b737f39c581f595b53c5cb19bd0b3f8da6c935e2ca06001600160a01b0383161415611cf057506001610759565b73d33526068d116ce69f19a9ee46f0bd304f21a51f6001600160a01b0383161415611d1d57506001610759565b7348c3399719b582dd63eb5aadf12a40b4c3f52fa26001600160a01b0383161415611d4a57506001610759565b735a98fcbea516cf06857215779fd812ca3bef1b326001600160a01b0383161415611d7757506001610759565b739f8f72aa9304c8b593d555f12ef6589cc3a579a26001600160a01b0383161415611da457506001610759565b731f9840a85d5af5bf1d1762f925bdaddc4201f9846001600160a01b0383161415611dd157506001610759565b73514910771af9ca656af840dff83e8264ecf986ca6001600160a01b0383161415611dfe57506001610759565b733c3a81e81dc49a522a592e7622a7e711c06bf3546001600160a01b038316141561122e57506001610759565b6001600160a01b0382166000908152600a602052604090205460ff1615158115151415611e6a5760405162461bcd60e51b815260040161073590613da9565b6001600160a01b0382166000908152600a602052604090819020805460ff1916831515179055517f70af441dbb427737e6a5ef2cf5b664321011765ce1d19ce4a69cd024e69d4f2f90611ec09084908490613cb4565b60405180910390a15050565b60405163e6a4390560e01b8152600090819073c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c69063e6a4390590611f0a9087908790600401613c14565b60206040518083038186803b158015611f2257600080fd5b505afa158015611f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5a9190613534565b91506001600160a01b038216611f825760405162461bcd60e51b815260040161073590613de5565b826001600160a01b0316846001600160a01b03161190509250929050565b6001808301805490910190819055811461079d5760405162461bcd60e51b815260040161073590613e21565b60005a9050611fdd60008335611fa0565b60008030612024611ffe611ff96101a088016101808901613518565b61281e565b612013611ff961018089016101608a01613518565b60c088013591016201a51c0161244c565b60405163733bf36160e11b9061203e90889060240161422c565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161207c9190613be4565b60006040518083038160008787f1925050503d80600081146120ba576040519150601f19603f3d011682016040523d82523d6000602084013e6120bf565b606091505b50909250905060018261212b576121286120e16101c087016101a08801613518565b6120f361018088016101608901613518565b61012088013561210b6101a08a016101808b01613518565b6101408a013561212160a08c0160808d016137b0565b6000612d8a565b90505b61213481612ee5565b60008061215c60c088013560e0890135886121576101c08c016101a08d01613518565b612f03565b915091508415156000600101547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c386858560405161219c93929190613cda565b60405180910390a350505050505050565b60005a90506121be60008335611fa0565b600080306121d360c08601356201dfb461244c565b60405163cdfd7ca960e01b906121ed90889060240161422c565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161222b9190613be4565b60006040518083038160008787f1925050503d8060008114612269576040519150601f19603f3d011682016040523d82523d6000602084013e61226e565b606091505b50909250905060018261212b5760006122a461229261018088016101608901613518565b610fb66101a089016101808a01613518565b5090506122d0816122bd6101c089016101a08a01613518565b61010089013563064e6cbb60e51b612f93565b91505061213481612ee5565b60005a90506122ed60008335611fa0565b60008030612319612309611ff961018088016101608901613518565b60c087013590620156fc0161244c565b60405163e88e0aab60e01b9061233390889060240161422c565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516123719190613be4565b60006040518083038160008787f1925050503d80600081146123af576040519150601f19603f3d011682016040523d82523d6000602084013e6123b4565b606091505b50909250905060018261212b576121286123d661018087016101608801613518565b6123e86101c088016101a08901613518565b6101208801356123fe60a08a0160808b016137b0565b600061309e565b60005a905061241660008335611fa0565b60008030612432612309611ff961018088016101608901613518565b604051637d7a756960e01b9061233390889060240161422c565b60006114d583836040518060400160405280600481526020016329a6989960e11b8152506131be565b60006003611b84565b825460009083111561249257506000612504565b600083815260048501602052604090205460ff16156124b357506005612504565b600083815260068501602052604090205460ff16156124d457506004612504565b60008381526002850160205260409020546124f157506003612504565b42821061250057506001612504565b5060025b9392505050565b808201828110156114d8576040805162461bcd60e51b81526020600480830191909152602482015263534d344560e01b604482015290519081900360640190fd5b60004261256160608501356301e1338061250b565b109050600161257660408501602086016137ca565b600481111561258157fe5b141561265e576000816125a5576125a06101c085016101a08601613518565b6125b2565b6008546001600160a01b03165b90506125ff816125ca61018087016101608801613518565b6101208701356125e26101a089016101808a01613518565b6101408901356125f860a08b0160808c016137b0565b6001612d8a565b61261b5760405162461bcd60e51b815260040161073590613d4f565b82156126585761263c8161263760e087013560c0880135613256565b6132ab565b6126585760405162461bcd60e51b815260040161073590613dc7565b50612812565b600261267060408501602086016137ca565b600481111561267b57fe5b141561274d5760006126aa61269861018086016101608701613518565b610fb66101a087016101808801613518565b5090506000826126cb576126c66101c086016101a08701613518565b6126d8565b6008546001600160a01b03165b90506126f2828261010088013563064e6cbb60e51b612f93565b61270e5760405162461bcd60e51b815260040161073590613d4f565b83156127465761272a8161263760e088013560c0890135613256565b6127465760405162461bcd60e51b815260040161073590613dc7565b5050612812565b600361275f60408501602086016137ca565b600481111561276a57fe5b14156127d05760008161278e576127896101c085016101a08601613518565b61279b565b6008546001600160a01b03165b90506125ff6127b261018086016101608701613518565b826101208701356127c960a0890160808a016137b0565b600161309e565b60046127e260408501602086016137ca565b60048111156127ed57fe5b141561280c5760008161278e576127896101c085016101a08601613518565b5061079d565b6112f96000843561331a565b60006001600160a01b0382166128375750612710610759565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03831614156128655750617918610759565b73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0383161415612893575061a410610759565b73dac17f958d2ee523a2206206994597c13d831ec76001600160a01b03831614156128c25750620101d0610759565b732260fac5e5542a773aa44fbcfedf7c193bc2c5996001600160a01b03831614156128f057506184d0610759565b734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b6001600160a01b038316141561291e5750617918610759565b736b3595068778dd592e39a122f4f5a5cf09c90fe26001600160a01b038316141561294c5750617918610759565b73ae7ab96520de3a18e5e111b5eaab095312d7fe846001600160a01b038316141561297b5750620109a0610759565b737f39c581f595b53c5cb19bd0b3f8da6c935e2ca06001600160a01b03831614156129a95750617918610759565b73d33526068d116ce69f19a9ee46f0bd304f21a51f6001600160a01b03831614156129d75750617918610759565b7348c3399719b582dd63eb5aadf12a40b4c3f52fa26001600160a01b0383161415612a055750619c40610759565b735a98fcbea516cf06857215779fd812ca3bef1b326001600160a01b0383161415612a34575062024608610759565b739f8f72aa9304c8b593d555f12ef6589cc3a579a26001600160a01b0383161415612a6257506184d0610759565b731f9840a85d5af5bf1d1762f925bdaddc4201f9846001600160a01b0383161415612a905750619088610759565b73514910771af9ca656af840dff83e8264ecf986ca6001600160a01b0383161415612abe5750617d00610759565b733c3a81e81dc49a522a592e7622a7e711c06bf3546001600160a01b0383161415612aec57506184d0610759565b5061ea60919050565b60006001611b84565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b60208310612b7a5780518252601f199092019160209182019101612b5b565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612bdc576040519150601f19603f3d011682016040523d82523d6000602084013e612be1565b606091505b5091509150818015612c0f575080511580612c0f5750808060200190516020811015612c0c57600080fd5b50515b612c49576040805162461bcd60e51b815260206004808301919091526024820152635448303560e01b604482015290519081900360640190fd5b5050505050565b6040516000906001600160a01b038516908390859084818181858888f193505050503d8060008114612c9e576040519150601f19603f3d011682016040523d82523d6000602084013e612ca3565b606091505b50509050806117b5576040805162461bcd60e51b815260206004808301919091526024820152632a2419a360e11b604482015290519081900360640190fd5b60006004611b84565b6009546001600160a01b0382811691161415612d195760405162461bcd60e51b815260040161073590613da9565b6001600160a01b038116612d3f5760405162461bcd60e51b815260040161073590613e3f565b600980546001600160a01b0319166001600160a01b0383161790556040517f99db624faf5b574db8409c17138c4894a18b552e2cd1dbe8c70b375a02748b6690611b74908390613c00565b600080803084612db057612d9d8861281e565b612da68b61281e565b01619c4001612db2565b5a5b604051633ed76f1760e01b90612dd6908e908e908e908e908e908e90602401613c51565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612e149190613be4565b60006040518083038160008787f1925050503d8060008114612e52576040519150601f19603f3d011682016040523d82523d6000602084013e612e57565b606091505b509150915081612ed857886001600160a01b03168a6001600160a01b031660008051602061430c8339815191528a84604051612e9492919061428d565b60405180910390a3866001600160a01b03168a6001600160a01b031660008051602061430c8339815191528884604051612ecf92919061428d565b60405180910390a35b5098975050505050505050565b80612ef957612ef4600061332e565b610747565b6107476000613353565b60008080612f118787613256565b9050612f246193ac610e865a889061244c565b92506000612f4982612f446000600301548761325690919063ffffffff16565b61336c565b9050612f55828261244c565b9250612f6133826132ab565b612f7d5760405162461bcd60e51b815260040161073590613dc7565b612f8785846132ab565b50505094509492505050565b600082612fa257506001613096565b600080306001600160a01b031661d6d8858989896000604051602401612fcb9493929190613c8b565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516130099190613be4565b60006040518083038160008787f1925050503d8060008114613047576040519150601f19603f3d011682016040523d82523d6000602084013e61304c565b606091505b50915091508161309257866001600160a01b0316866001600160a01b031660008051602061430c833981519152878460405161308992919061428d565b60405180910390a35b5090505b949350505050565b6000836130ad575060016131b5565b60008030846130c8576130bf8961281e565b614e20016130ca565b5a5b60405163e5b1be6560e01b906130ea908c908c908c908c90602401613c8b565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516131289190613be4565b60006040518083038160008787f1925050503d8060008114613166576040519150601f19603f3d011682016040523d82523d6000602084013e61316b565b606091505b5091509150816131b157876001600160a01b0316876001600160a01b031660008051602061430c83398151915288846040516131a892919061428d565b60405180910390a35b5090505b95945050505050565b818303818482111561324e5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156132135781810151838201526020016131fb565b50505050905090810190601f1680156132405780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509392505050565b60008115806132715750508082028282828161326e57fe5b04145b6114d8576040805162461bcd60e51b81526020600480830191909152602482015263534d324160e01b604482015290519081900360640190fd5b6000816132ba575060016114d8565b6132ce83836132c9600061281e565b613382565b9050801515836001600160a01b03167fdbef2fc26e7694e7a1c5a4801b1ad144136d149cf76f310a780689b4087f0ffe8460405161330c9190614284565b60405180910390a392915050565b600090815260029091016020526040812055565b600181810154600090815260069092016020526040909120805460ff19169091179055565b6001810154600090815260029091016020526040812055565b600081831061337b57816114d5565b5090919050565b6040516000906001600160a01b038516908390859084818181858888f193505050503d80600081146133d0576040519150601f19603f3d011682016040523d82523d6000602084013e6133d5565b606091505b509095945050505050565b60405180606001604052806133f3613407565b815260006020820181905260409091015290565b6040805161028081019091526000808252602082019081526020016000151581526020016000815260200160001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000151581526020016000815260200160008152602001600081525090565b8035610759816142f6565b8035801515811461075957600080fd5b80356005811061075957600080fd5b600061010082840312156134fe578081fd5b50919050565b803563ffffffff8116811461075957600080fd5b600060208284031215613529578081fd5b8135612504816142f6565b600060208284031215613545578081fd5b8151612504816142f6565b60008060408385031215613562578081fd5b823561356d816142f6565b9150602083013561357d816142f6565b809150509250929050565b60008060006060848603121561359c578081fd5b83356135a7816142f6565b925060208401356135b7816142f6565b929592945050506040919091013590565b60008060008060008060c087890312156135e0578182fd5b86356135eb816142f6565b955060208701356135fb816142f6565b9450604087013593506060870135613612816142f6565b92506080870135915061362760a088016134cd565b90509295509295509295565b60008060008060808587031215613648578384fd5b8435613653816142f6565b93506020850135613663816142f6565b925060408501359150613678606086016134cd565b905092959194509250565b60008060008060608587031215613698578182fd5b84356136a3816142f6565b9350602085013567ffffffffffffffff808211156136bf578384fd5b818701915087601f8301126136d2578384fd5b8135818111156136e0578485fd5b88602080830285010111156136f3578485fd5b602083019550809450505050613678604086016134cd565b6000806040838503121561371d578182fd5b8235613728816142f6565b9150613736602084016134cd565b90509250929050565b60008060208385031215613751578182fd5b823567ffffffffffffffff80821115613768578384fd5b818501915085601f83011261377b578384fd5b813581811115613789578485fd5b8660206102808302850101111561379e578485fd5b60209290920196919550909350505050565b6000602082840312156137c1578081fd5b6114d5826134cd565b6000602082840312156137db578081fd5b6114d5826134dd565b600061010082840312156137f6578081fd5b6114d583836134ec565b600061016082840312156134fe578081fd5b600061028082840312156134fe578081fd5b6000610280808385031215613837578182fd5b613840816142a6565b905082358152613852602084016134dd565b6020820152613863604084016134cd565b60408201526060830135606082015261387e608084016134cd565b608082015260a083013560a082015260c083013560c082015260e083013560e08201526101008084013581830152506101208084013581830152506101408084013581830152506101606138d38185016134c2565b908201526101806138e58482016134c2565b908201526101a06138f78482016134c2565b908201526101c083810135908201526101e0808401359082015261020061391f8185016134cd565b9082015261022083810135908201526102408084013590820152610260928301359281019290925250919050565b600061012082840312156134fe578081fd5b600060208284031215613970578081fd5b5035919050565b600060208284031215613988578081fd5b5051919050565b600080604083850312156139a1578182fd5b50508035926020909101359150565b6001600160a01b03169052565b15159052565b600081518084526139db8160208601602086016142ca565b601f01601f19169290920160200192915050565b600581106139f957fe5b9052565b8035613a08816142f6565b6001600160a01b039081168352602082013590613a24826142f6565b80821660208501526040830135604085015260608301356060850152613a4c608084016134cd565b1515608085015260a08301359150613a63826142f6565b1660a083015260c08181013590830152613a7f60e08201613504565b6112f960e0840182613bda565b80358252613a9c602082016134dd565b613aa960208401826139ef565b50613ab6604082016134cd565b613ac360408401826139bd565b5060608101356060830152613ada608082016134cd565b613ae760808401826139bd565b5060a081013560a083015260c081013560c083015260e081013560e0830152610100808201358184015250610120808201358184015250610140808201358184015250610160613b388183016134c2565b613b44828501826139b0565b5050610180613b548183016134c2565b613b60828501826139b0565b50506101a0613b708183016134c2565b613b7c828501826139b0565b50506101c081810135908301526101e08082013590830152610200613ba28183016134cd565b613bae828501826139bd565b50506102208181013590830152610240808201359083015261026090810135910152565b61ffff169052565b63ffffffff169052565b60008251613bf68184602087016142ca565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b0396871681529486166020860152604085019390935293166060830152608082019290925290151560a082015260c00190565b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b6001600160a01b039290921682521515602082015260400190565b901515815260200190565b600060608252613ced60608301866139c3565b60208301949094525060400152919050565b6020810160068310613d0d57fe5b91905290565b6020808252600490820152632a22181b60e11b604082015260600190565b6020808252600490820152635444314360e01b604082015260600190565b60208082526004908201526315110c4d60e21b604082015260600190565b6020808252600490820152635444323160e01b604082015260600190565b6020808252600490820152630544430360e41b604082015260600190565b6020808252600490820152635444303160e01b604082015260600190565b6020808252600490820152630544434360e41b604082015260600190565b6020808252600490820152634f53313760e01b604082015260600190565b6020808252600490820152632a221a9960e11b604082015260600190565b60208082526004908201526327a99b9960e11b604082015260600190565b6020808252600490820152632a22181960e11b604082015260600190565b8581526001600160a01b0385166020808301919091526080604083018190528201849052600090859060a08401835b87811015613eb657613ea682613ea1866134dd565b6139ef565b9282019290820190600101613e8c565b5080935050505082151560608301529695505050505050565b8381526101408101613ee460208301856139fd565b82610120830152949350505050565b8381526101a08101613f1060208301613f0b866134c2565b6139b0565b613f1c602085016134c2565b613f2960408401826139b0565b506040840135606083015260608401356080830152608084013560a083015260a084013560c0830152613f5e60c085016134cd565b613f6b60e08401826139bd565b50613f7860e085016134cd565b610100613f87818501836139bd565b613f928187016134c2565b915050610120613fa4818501836139b0565b6101409150808601358285015250613fbd818601613504565b9050613fcd610160840182613bda565b5082610180830152949350505050565b8281526102a081016125046020830184613a8c565b828152610140810161400a60208301613f0b856134c2565b614016602084016134c2565b61402360408401826139b0565b506040830135606083015260608301356080830152608083013560a083015261404e60a084016134cd565b61405b60c08401826139bd565b5061406860c084016134c2565b61407560e08401826139b0565b5061010060e08401358184015261408d818501613504565b905061324e610120840182613bda565b918252602082015260400190565b9485526001600160a01b0393841660208601526040850192909252606084015216608082015260a00190565b60006102e08201905083518051835260208101516140f860208501826139ef565b50604081015161410b60408501826139bd565b5060608101516060840152608081015161412860808501826139bd565b5060a081015160a084015260c081015160c084015260e081015160e08401526101008082015181850152506101208082015181850152506101408082015181850152506101608082015161417e828601826139b0565b505061018080820151614193828601826139b0565b50506101a0808201516141a8828601826139b0565b50506101c081810151908401526101e08082015190840152610200808201516141d3828601826139bd565b505061022081810151908401526102408082015190840152610260908101519083015260208401516142096102808401826139b0565b50604084015161421d6102a0840182613bd2565b50826102c08301529392505050565b61028081016114d88284613a8c565b6102e0810161424a8287613a8c565b6001600160a01b039490941661028082015261ffff929092166102a08301526102c090910152919050565b61ffff91909116815260200190565b90815260200190565b60008382526040602083015261309660408301846139c3565b60405181810167ffffffffffffffff811182821017156142c257fe5b604052919050565b60005b838110156142e55781810151838201526020016142cd565b838111156117b55750506000910152565b6001600160a01b038116811461074757600080fdfe786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b211592a264697066735822122099bde760c5a3a45475e145709e72c67d165673645fd1abfea9ffbe368107fd4764736f6c63430007060033

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

000000000000000000000000f4418d9fe76a788f2868a558dd216549ad2d869b0000000000000000000000003a1d749fa4a9e650fce844ff1c58c5faf7e2a9d1

-----Decoded View---------------
Arg [0] : _factoryGovernor (address): 0xF4418d9fe76A788F2868a558dD216549aD2d869B
Arg [1] : _bot (address): 0x3a1D749fa4a9E650FCe844fF1C58C5faf7e2a9D1

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


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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