Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
Latest 25 from a total of 4,689 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Set Order Disabl... | 17608758 | 491 days ago | IN | 0 ETH | 0.00049996 | ||||
Set Order Disabl... | 17608757 | 491 days ago | IN | 0 ETH | 0.00048857 | ||||
Set Order Disabl... | 17608757 | 491 days ago | IN | 0 ETH | 0.00048857 | ||||
Set Order Disabl... | 17608757 | 491 days ago | IN | 0 ETH | 0.00072409 | ||||
Set Order Disabl... | 17608756 | 491 days ago | IN | 0 ETH | 0.00048687 | ||||
Set Order Disabl... | 17608755 | 491 days ago | IN | 0 ETH | 0.00049711 | ||||
Set Order Disabl... | 17608755 | 491 days ago | IN | 0 ETH | 0.00049711 | ||||
Set Order Disabl... | 17608755 | 491 days ago | IN | 0 ETH | 0.00073674 | ||||
Set Order Disabl... | 17608754 | 491 days ago | IN | 0 ETH | 0.00051153 | ||||
Set Order Disabl... | 17608753 | 491 days ago | IN | 0 ETH | 0.00046564 | ||||
Set Order Disabl... | 17608753 | 491 days ago | IN | 0 ETH | 0.00046564 | ||||
Set Order Disabl... | 17608752 | 491 days ago | IN | 0 ETH | 0.00071591 | ||||
Set Order Disabl... | 17608752 | 491 days ago | IN | 0 ETH | 0.00048305 | ||||
Set Order Disabl... | 17608751 | 491 days ago | IN | 0 ETH | 0.00050826 | ||||
Set Order Disabl... | 17608751 | 491 days ago | IN | 0 ETH | 0.00050826 | ||||
Set Order Disabl... | 17608750 | 491 days ago | IN | 0 ETH | 0.00073046 | ||||
Set Order Disabl... | 17608749 | 491 days ago | IN | 0 ETH | 0.00049919 | ||||
Set Order Disabl... | 17608749 | 491 days ago | IN | 0 ETH | 0.00049919 | ||||
Set Order Disabl... | 17608748 | 491 days ago | IN | 0 ETH | 0.0005117 | ||||
Set Order Disabl... | 17608748 | 491 days ago | IN | 0 ETH | 0.00075836 | ||||
Set Order Disabl... | 17608747 | 491 days ago | IN | 0 ETH | 0.00052419 | ||||
Set Order Disabl... | 17608747 | 491 days ago | IN | 0 ETH | 0.00052419 | ||||
Set Order Disabl... | 17608746 | 491 days ago | IN | 0 ETH | 0.00052741 | ||||
Set Order Disabl... | 17608746 | 491 days ago | IN | 0 ETH | 0.00078166 | ||||
Set Order Disabl... | 17608744 | 491 days ago | IN | 0 ETH | 0.00055804 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
17607632 | 491 days ago | 0.00500728 ETH | ||||
17607632 | 491 days ago | 0.00594721 ETH | ||||
17607479 | 491 days ago | 0.00054772 ETH | ||||
17607479 | 491 days ago | 0.01150222 ETH | ||||
17607399 | 491 days ago | 0.00542028 ETH | ||||
17607399 | 491 days ago | 0.00555821 ETH | ||||
17607246 | 491 days ago | 0.00054892 ETH | ||||
17607246 | 491 days ago | 0.01152742 ETH | ||||
17607216 | 491 days ago | 0.00524447 ETH | ||||
17607216 | 491 days ago | 0.00572402 ETH | ||||
17607065 | 491 days ago | 0.00054842 ETH | ||||
17607065 | 491 days ago | 0.01151692 ETH | ||||
17606889 | 491 days ago | 0.00637179 ETH | ||||
17606889 | 491 days ago | 0.0045907 ETH | ||||
17606889 | 491 days ago | 0.00552702 ETH | ||||
17606889 | 491 days ago | 0.00543547 ETH | ||||
17606739 | 491 days ago | 0.00054812 ETH | ||||
17606739 | 491 days ago | 0.01151062 ETH | ||||
17606739 | 491 days ago | 0.00054812 ETH | ||||
17606739 | 491 days ago | 0.01151062 ETH | ||||
17606476 | 491 days ago | 0.00569842 ETH | ||||
17606476 | 491 days ago | 0.00528707 ETH | ||||
17606324 | 491 days ago | 0.00054927 ETH | ||||
17606324 | 491 days ago | 0.01153477 ETH | ||||
17606277 | 491 days ago | 0.00509271 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
TwapDelay
Compiler Version
v0.7.6+commit.7338295f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; pragma abicoder v2; import './interfaces/ITwapPair.sol'; import './interfaces/ITwapDelay.sol'; import './interfaces/IWETH.sol'; import './libraries/SafeMath.sol'; import './libraries/Orders.sol'; import './libraries/TokenShares.sol'; import './libraries/AddLiquidity.sol'; import './libraries/WithdrawHelper.sol'; contract TwapDelay is ITwapDelay { using SafeMath for uint256; using Orders for Orders.Data; using TokenShares for TokenShares.Data; Orders.Data internal orders; TokenShares.Data internal tokenShares; uint256 private constant ORDER_CANCEL_TIME = 24 hours; uint256 private constant BOT_EXECUTION_TIME = 20 minutes; uint256 private constant ORDER_LIFESPAN = 48 hours; uint16 private constant MAX_TOLERANCE = 10; address public override owner; mapping(address => bool) public override isBot; mapping(address => uint16) public override tolerance; constructor( address _factory, address _weth, address _bot ) { orders.factory = _factory; owner = msg.sender; isBot[_bot] = true; orders.gasPrice = tx.gasprice - (tx.gasprice % 1e6); tokenShares.weth = _weth; orders.delay = 30 minutes; orders.maxGasLimit = 5_000_000; orders.gasPriceInertia = 20_000_000; orders.maxGasPriceImpact = 1_000_000; orders.setTransferGasCost(address(0), Orders.ETHER_TRANSFER_CALL_COST); emit OwnerSet(msg.sender); } function getTransferGasCost(address token) external view override returns (uint256 gasCost) { return orders.transferGasCosts[token]; } function getDepositOrder(uint256 orderId) external view override returns (Orders.DepositOrder memory order) { (order, , ) = orders.getDepositOrder(orderId); } function getWithdrawOrder(uint256 orderId) external view override returns (Orders.WithdrawOrder memory order) { return orders.getWithdrawOrder(orderId); } function getSellOrder(uint256 orderId) external view override returns (Orders.SellOrder memory order) { (order, ) = orders.getSellOrder(orderId); } function getBuyOrder(uint256 orderId) external view override returns (Orders.BuyOrder memory order) { (order, ) = orders.getBuyOrder(orderId); } function getDepositDisabled(address pair) external view override returns (bool) { return orders.getDepositDisabled(pair); } function getWithdrawDisabled(address pair) external view override returns (bool) { return orders.getWithdrawDisabled(pair); } function getBuyDisabled(address pair) external view override returns (bool) { return orders.getBuyDisabled(pair); } function getSellDisabled(address pair) external view override returns (bool) { return orders.getSellDisabled(pair); } function getOrderStatus(uint256 orderId) external view override returns (Orders.OrderStatus) { return orders.getOrderStatus(orderId); } uint256 private locked; modifier lock() { require(locked == 0, 'TD06'); locked = 1; _; locked = 0; } function factory() external view override returns (address) { return orders.factory; } function totalShares(address token) external view override returns (uint256) { return tokenShares.totalShares[token]; } function weth() external view override returns (address) { return tokenShares.weth; } function delay() external view override returns (uint32) { return orders.delay; } function lastProcessedOrderId() external view returns (uint256) { return orders.lastProcessedOrderId; } function newestOrderId() external view returns (uint256) { return orders.newestOrderId; } function getOrder(uint256 orderId) external view returns (Orders.OrderType orderType, uint32 validAfterTimestamp) { return orders.getOrder(orderId); } function isOrderCanceled(uint256 orderId) external view returns (bool) { return orders.canceled[orderId]; } function maxGasLimit() external view override returns (uint256) { return orders.maxGasLimit; } function maxGasPriceImpact() external view override returns (uint256) { return orders.maxGasPriceImpact; } function gasPriceInertia() external view override returns (uint256) { return orders.gasPriceInertia; } function gasPrice() external view override returns (uint256) { return orders.gasPrice; } function setOrderDisabled( address pair, Orders.OrderType orderType, bool disabled ) external payable override { require(msg.sender == owner, 'TD00'); orders.setOrderDisabled(pair, orderType, disabled); } function setOwner(address _owner) external payable override { require(msg.sender == owner, 'TD00'); // require(_owner != owner, 'TD01'); // Comment out to save size require(_owner != address(0), 'TD02'); owner = _owner; emit OwnerSet(_owner); } function setBot(address _bot, bool _isBot) external payable override { require(msg.sender == owner, 'TD00'); // require(_isBot != isBot[_bot], 'TD01'); // Comment out to save size isBot[_bot] = _isBot; emit BotSet(_bot, _isBot); } function setMaxGasLimit(uint256 _maxGasLimit) external payable override { require(msg.sender == owner, 'TD00'); orders.setMaxGasLimit(_maxGasLimit); } function setDelay(uint32 _delay) external payable override { require(msg.sender == owner, 'TD00'); // require(_delay != orders.delay, 'TD01'); // Comment out to save size orders.delay = _delay; emit DelaySet(_delay); } function setGasPriceInertia(uint256 _gasPriceInertia) external payable override { require(msg.sender == owner, 'TD00'); orders.setGasPriceInertia(_gasPriceInertia); } function setMaxGasPriceImpact(uint256 _maxGasPriceImpact) external payable override { require(msg.sender == owner, 'TD00'); orders.setMaxGasPriceImpact(_maxGasPriceImpact); } function setTransferGasCost(address token, uint256 gasCost) external payable override { require(msg.sender == owner, 'TD00'); orders.setTransferGasCost(token, gasCost); } function setTolerance(address pair, uint16 amount) external payable override { require(msg.sender == owner, 'TD00'); require(amount <= MAX_TOLERANCE, 'TD54'); tolerance[pair] = amount; emit ToleranceSet(pair, amount); } function deposit(Orders.DepositParams calldata depositParams) external payable override lock returns (uint256 orderId) { orders.deposit(depositParams, tokenShares); return orders.newestOrderId; } function withdraw(Orders.WithdrawParams calldata withdrawParams) external payable override lock returns (uint256 orderId) { orders.withdraw(withdrawParams); return orders.newestOrderId; } function sell(Orders.SellParams calldata sellParams) external payable override lock returns (uint256 orderId) { orders.sell(sellParams, tokenShares); return orders.newestOrderId; } function buy(Orders.BuyParams calldata buyParams) external payable override lock returns (uint256 orderId) { orders.buy(buyParams, tokenShares); return orders.newestOrderId; } function execute(uint256 n) external payable override lock { emit Execute(msg.sender, n); uint256 gasBefore = gasleft(); bool orderExecuted; bool senderCanExecute = isBot[msg.sender] || isBot[address(0)]; for (uint256 i; i < n; ++i) { if (orders.canceled[orders.lastProcessedOrderId + 1]) { orders.dequeueCanceledOrder(); continue; } (Orders.OrderType orderType, uint256 validAfterTimestamp) = orders.getNextOrder(); if (orderType == Orders.OrderType.Empty || validAfterTimestamp >= block.timestamp) { break; } require(senderCanExecute || block.timestamp >= validAfterTimestamp + BOT_EXECUTION_TIME, 'TD00'); orderExecuted = true; if (orderType == Orders.OrderType.Deposit) { executeDeposit(); } else if (orderType == Orders.OrderType.Withdraw) { executeWithdraw(); } else if (orderType == Orders.OrderType.Sell) { executeSell(); } else if (orderType == Orders.OrderType.Buy) { executeBuy(); } } if (orderExecuted) { orders.updateGasPrice(gasBefore.sub(gasleft())); } } function executeDeposit() internal { uint256 gasStart = gasleft(); (Orders.DepositOrder memory depositOrder, uint256 amountLimit0, uint256 amountLimit1) = orders .dequeueDepositOrder(); (, address token0, address token1) = orders.getPairInfo(depositOrder.pairId); (bool executionSuccess, bytes memory data) = address(this).call{ gas: depositOrder.gasLimit.sub( Orders.ORDER_BASE_COST.add(orders.transferGasCosts[token0]).add(orders.transferGasCosts[token1]) ) }(abi.encodeWithSelector(this._executeDeposit.selector, depositOrder, amountLimit0, amountLimit1)); bool refundSuccess = true; if (!executionSuccess) { refundSuccess = refundTokens( depositOrder.to, token0, depositOrder.share0, token1, depositOrder.share1, depositOrder.unwrap ); } finalizeOrder(refundSuccess); (uint256 gasUsed, uint256 ethRefund) = refund( depositOrder.gasLimit, depositOrder.gasPrice, gasStart, depositOrder.to ); emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund); } function executeWithdraw() internal { uint256 gasStart = gasleft(); Orders.WithdrawOrder memory withdrawOrder = orders.dequeueWithdrawOrder(); (bool executionSuccess, bytes memory data) = address(this).call{ gas: withdrawOrder.gasLimit.sub(Orders.ORDER_BASE_COST.add(Orders.PAIR_TRANSFER_COST)) }(abi.encodeWithSelector(this._executeWithdraw.selector, withdrawOrder)); bool refundSuccess = true; if (!executionSuccess) { (address pair, , ) = orders.getPairInfo(withdrawOrder.pairId); refundSuccess = Orders.refundLiquidity( pair, withdrawOrder.to, withdrawOrder.liquidity, this._refundLiquidity.selector ); } finalizeOrder(refundSuccess); (uint256 gasUsed, uint256 ethRefund) = refund( withdrawOrder.gasLimit, withdrawOrder.gasPrice, gasStart, withdrawOrder.to ); emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund); } function executeSell() internal { uint256 gasStart = gasleft(); (Orders.SellOrder memory sellOrder, uint256 amountLimit) = orders.dequeueSellOrder(); (, address token0, address token1) = orders.getPairInfo(sellOrder.pairId); (bool executionSuccess, bytes memory data) = address(this).call{ gas: sellOrder.gasLimit.sub( Orders.ORDER_BASE_COST.add(orders.transferGasCosts[sellOrder.inverse ? token1 : token0]) ) }(abi.encodeWithSelector(this._executeSell.selector, sellOrder, amountLimit)); bool refundSuccess = true; if (!executionSuccess) { refundSuccess = refundToken( sellOrder.inverse ? token1 : token0, sellOrder.to, sellOrder.shareIn, sellOrder.unwrap ); } finalizeOrder(refundSuccess); (uint256 gasUsed, uint256 ethRefund) = refund(sellOrder.gasLimit, sellOrder.gasPrice, gasStart, sellOrder.to); emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund); } function executeBuy() internal { uint256 gasStart = gasleft(); (Orders.BuyOrder memory buyOrder, uint256 amountLimit) = orders.dequeueBuyOrder(); (, address token0, address token1) = orders.getPairInfo(buyOrder.pairId); (bool executionSuccess, bytes memory data) = address(this).call{ gas: buyOrder.gasLimit.sub( Orders.ORDER_BASE_COST.add(orders.transferGasCosts[buyOrder.inverse ? token1 : token0]) ) }(abi.encodeWithSelector(this._executeBuy.selector, buyOrder, amountLimit)); bool refundSuccess = true; if (!executionSuccess) { refundSuccess = refundToken( buyOrder.inverse ? token1 : token0, buyOrder.to, buyOrder.shareInMax, buyOrder.unwrap ); } finalizeOrder(refundSuccess); (uint256 gasUsed, uint256 ethRefund) = refund(buyOrder.gasLimit, buyOrder.gasPrice, gasStart, buyOrder.to); emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund); } function finalizeOrder(bool refundSuccess) private { if (!refundSuccess) { orders.markRefundFailed(); } else { orders.forgetLastProcessedOrder(); } } function refund( uint256 gasLimit, uint256 gasPriceInOrder, uint256 gasStart, address to ) private returns (uint256 gasUsed, uint256 leftOver) { uint256 feeCollected = gasLimit.mul(gasPriceInOrder); gasUsed = gasStart.sub(gasleft()).add(Orders.REFUND_BASE_COST); uint256 actualRefund = Math.min(feeCollected, gasUsed.mul(orders.gasPrice)); leftOver = feeCollected.sub(actualRefund); require(refundEth(msg.sender, actualRefund), 'TD40'); refundEth(payable(to), leftOver); } function refundEth(address payable to, uint256 value) internal returns (bool success) { if (value == 0) { return true; } success = TransferHelper.transferETH(to, value, orders.transferGasCosts[address(0)]); emit EthRefund(to, success, value); } function refundToken( address token, address to, uint256 share, bool unwrap ) private returns (bool) { if (share == 0) { return true; } (bool success, bytes memory data) = address(this).call{ gas: orders.transferGasCosts[token] }( abi.encodeWithSelector(this._refundToken.selector, token, to, share, unwrap) ); if (!success) { emit RefundFailed(to, token, share, data); } return success; } function refundTokens( address to, address token0, uint256 share0, address token1, uint256 share1, bool unwrap ) private returns (bool) { (bool success, bytes memory data) = address(this).call{ gas: orders.transferGasCosts[token0].add(orders.transferGasCosts[token1]) }(abi.encodeWithSelector(this._refundTokens.selector, to, token0, share0, token1, share1, unwrap)); if (!success) { emit RefundFailed(to, token0, share0, data); emit RefundFailed(to, token1, share1, data); } return success; } function _refundTokens( address to, address token0, uint256 share0, address token1, uint256 share1, bool unwrap ) external payable { // no need to check sender, because it is checked in _refundToken _refundToken(token0, to, share0, unwrap); _refundToken(token1, to, share1, unwrap); } function _refundToken( address token, address to, uint256 share, bool unwrap ) public payable { require(msg.sender == address(this), 'TD00'); if (token == tokenShares.weth && unwrap) { uint256 amount = tokenShares.sharesToAmount(token, share, 0, to); IWETH(tokenShares.weth).withdraw(amount); TransferHelper.safeTransferETH(to, amount, orders.transferGasCosts[address(0)]); } else { TransferHelper.safeTransfer(token, to, tokenShares.sharesToAmount(token, share, 0, to)); } } function _refundLiquidity( address pair, address to, uint256 liquidity ) external payable { require(msg.sender == address(this), 'TD00'); return TransferHelper.safeTransfer(pair, to, liquidity); } function _executeDeposit( Orders.DepositOrder calldata depositOrder, uint256 amountLimit0, uint256 amountLimit1 ) external payable { require(msg.sender == address(this), 'TD00'); require(depositOrder.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04'); ( Orders.PairInfo memory pairInfo, uint256 amount0Left, uint256 amount1Left, uint256 swapToken ) = _initialDeposit(depositOrder, amountLimit0, amountLimit1); if (depositOrder.swap && swapToken != 0) { bytes memory data = encodePriceInfo(pairInfo.pair, depositOrder.priceAccumulator, depositOrder.timestamp); if (amount0Left != 0 && swapToken == 1) { uint256 extraAmount1; (amount0Left, extraAmount1) = AddLiquidity.swapDeposit0( pairInfo.pair, pairInfo.token0, amount0Left, depositOrder.minSwapPrice, tolerance[pairInfo.pair], data ); amount1Left = amount1Left.add(extraAmount1); } else if (amount1Left != 0 && swapToken == 2) { uint256 extraAmount0; (extraAmount0, amount1Left) = AddLiquidity.swapDeposit1( pairInfo.pair, pairInfo.token1, amount1Left, depositOrder.maxSwapPrice, tolerance[pairInfo.pair], data ); amount0Left = amount0Left.add(extraAmount0); } } if (amount0Left != 0 && amount1Left != 0) { (amount0Left, amount1Left, ) = AddLiquidity.addLiquidityAndMint( pairInfo.pair, depositOrder.to, pairInfo.token0, pairInfo.token1, amount0Left, amount1Left ); } AddLiquidity._refundDeposit(depositOrder.to, pairInfo.token0, pairInfo.token1, amount0Left, amount1Left); } function _initialDeposit( Orders.DepositOrder calldata depositOrder, uint256 amountLimit0, uint256 amountLimit1 ) private returns ( Orders.PairInfo memory pairInfo, uint256 amount0Left, uint256 amount1Left, uint256 swapToken ) { pairInfo = orders.pairs[depositOrder.pairId]; uint256 amount0Desired = tokenShares.sharesToAmount( pairInfo.token0, depositOrder.share0, amountLimit0, depositOrder.to ); uint256 amount1Desired = tokenShares.sharesToAmount( pairInfo.token1, depositOrder.share1, amountLimit1, depositOrder.to ); ITwapPair(pairInfo.pair).sync(); (amount0Left, amount1Left, swapToken) = AddLiquidity.addLiquidityAndMint( pairInfo.pair, depositOrder.to, pairInfo.token0, pairInfo.token1, amount0Desired, amount1Desired ); } function _executeWithdraw(Orders.WithdrawOrder calldata withdrawOrder) external payable { require(msg.sender == address(this), 'TD00'); require(withdrawOrder.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04'); (address pair, address token0, address token1) = orders.getPairInfo(withdrawOrder.pairId); ITwapPair(pair).sync(); TransferHelper.safeTransfer(pair, pair, withdrawOrder.liquidity); uint256 wethAmount; uint256 amount0; uint256 amount1; if (withdrawOrder.unwrap && (token0 == tokenShares.weth || token1 == tokenShares.weth)) { bool success; (success, wethAmount, amount0, amount1) = WithdrawHelper.withdrawAndUnwrap( token0, token1, pair, tokenShares.weth, withdrawOrder.to, orders.transferGasCosts[address(0)] ); if (!success) { tokenShares.onUnwrapFailed(withdrawOrder.to, wethAmount); } } else { (amount0, amount1) = ITwapPair(pair).burn(withdrawOrder.to); } require(amount0 >= withdrawOrder.amount0Min && amount1 >= withdrawOrder.amount1Min, 'TD03'); } function _executeBuy(Orders.BuyOrder calldata buyOrder, uint256 amountLimit) external payable { require(msg.sender == address(this), 'TD00'); require(buyOrder.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04'); (address pairAddress, address tokenIn, address tokenOut) = _getPairAndTokens(buyOrder.pairId, buyOrder.inverse); uint256 amountInMax = tokenShares.sharesToAmount(tokenIn, buyOrder.shareInMax, amountLimit, buyOrder.to); ITwapPair(pairAddress).sync(); bytes memory priceInfo = encodePriceInfo(pairAddress, buyOrder.priceAccumulator, buyOrder.timestamp); uint256 amountIn; uint256 amountOut; uint256 reserveOut; { // scope for reserve out logic, avoids stack too deep errors (uint112 reserve0, uint112 reserve1) = ITwapPair(pairAddress).getReserves(); // subtract 1 to prevent reserve going to 0 reserveOut = uint256(buyOrder.inverse ? reserve0 : reserve1).sub(1); } { // scope for partial fill logic, avoids stack too deep errors address oracle = ITwapPair(pairAddress).oracle(); uint256 swapFee = ITwapPair(pairAddress).swapFee(); (amountIn, amountOut) = ITwapOracle(oracle).getSwapAmountInMaxOut( buyOrder.inverse, swapFee, buyOrder.amountOut, priceInfo ); uint256 amountInMaxScaled; if (amountOut > reserveOut) { amountInMaxScaled = amountInMax.mul(reserveOut).ceil_div(buyOrder.amountOut); (amountIn, amountOut) = ITwapOracle(oracle).getSwapAmountInMinOut( buyOrder.inverse, swapFee, reserveOut, priceInfo ); } else { amountInMaxScaled = amountInMax; amountOut = buyOrder.amountOut; // Truncate to desired out } require(amountInMaxScaled >= amountIn, 'TD08'); if (amountInMax > amountIn) { if (tokenIn == tokenShares.weth && buyOrder.unwrap) { _forceEtherTransfer(buyOrder.to, amountInMax.sub(amountIn)); } else { TransferHelper.safeTransfer(tokenIn, buyOrder.to, amountInMax.sub(amountIn)); } } TransferHelper.safeTransfer(tokenIn, pairAddress, amountIn); } amountOut = amountOut.sub(tolerance[pairAddress]); uint256 amount0Out; uint256 amount1Out; if (buyOrder.inverse) { amount0Out = amountOut; } else { amount1Out = amountOut; } if (tokenOut == tokenShares.weth && buyOrder.unwrap) { ITwapPair(pairAddress).swap(amount0Out, amount1Out, address(this), priceInfo); _forceEtherTransfer(buyOrder.to, amountOut); } else { ITwapPair(pairAddress).swap(amount0Out, amount1Out, buyOrder.to, priceInfo); } } function _executeSell(Orders.SellOrder calldata sellOrder, uint256 amountLimit) external payable { require(msg.sender == address(this), 'TD00'); require(sellOrder.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04'); (address pairAddress, address tokenIn, address tokenOut) = _getPairAndTokens( sellOrder.pairId, sellOrder.inverse ); ITwapPair(pairAddress).sync(); bytes memory priceInfo = encodePriceInfo(pairAddress, sellOrder.priceAccumulator, sellOrder.timestamp); uint256 amountOut = _executeSellHelper(sellOrder, amountLimit, pairAddress, tokenIn, priceInfo); (uint256 amount0Out, uint256 amount1Out) = sellOrder.inverse ? (amountOut, uint256(0)) : (uint256(0), amountOut); if (tokenOut == tokenShares.weth && sellOrder.unwrap) { ITwapPair(pairAddress).swap(amount0Out, amount1Out, address(this), priceInfo); _forceEtherTransfer(sellOrder.to, amountOut); } else { ITwapPair(pairAddress).swap(amount0Out, amount1Out, sellOrder.to, priceInfo); } } function _executeSellHelper( Orders.SellOrder calldata sellOrder, uint256 amountLimit, address pairAddress, address tokenIn, bytes memory priceInfo ) internal returns (uint256 amountOut) { uint256 reserveOut; { // scope for determining reserve out, avoids stack too deep errors (uint112 reserve0, uint112 reserve1) = ITwapPair(pairAddress).getReserves(); // subtract 1 to prevent reserve going to 0 reserveOut = uint256(sellOrder.inverse ? reserve0 : reserve1).sub(1); } { // scope for calculations, avoids stack too deep errors address oracle = ITwapPair(pairAddress).oracle(); uint256 swapFee = ITwapPair(pairAddress).swapFee(); uint256 amountIn = tokenShares.sharesToAmount(tokenIn, sellOrder.shareIn, amountLimit, sellOrder.to); amountOut = sellOrder.inverse ? ITwapOracle(oracle).getSwapAmount0Out(swapFee, amountIn, priceInfo) : ITwapOracle(oracle).getSwapAmount1Out(swapFee, amountIn, priceInfo); uint256 amountOutMinScaled; if (amountOut > reserveOut) { amountOutMinScaled = sellOrder.amountOutMin.mul(reserveOut).div(amountOut); uint256 _amountIn = amountIn; (amountIn, amountOut) = ITwapOracle(oracle).getSwapAmountInMinOut( sellOrder.inverse, swapFee, reserveOut, priceInfo ); if (tokenIn == tokenShares.weth && sellOrder.unwrap) { _forceEtherTransfer(sellOrder.to, _amountIn.sub(amountIn)); } else { TransferHelper.safeTransfer(tokenIn, sellOrder.to, _amountIn.sub(amountIn)); } } else { amountOutMinScaled = sellOrder.amountOutMin; } amountOut = amountOut.sub(tolerance[pairAddress]); require(amountOut >= amountOutMinScaled, 'TD37'); TransferHelper.safeTransfer(tokenIn, pairAddress, amountIn); } } function _getPairAndTokens(uint32 pairId, bool pairInversed) private view returns ( address, address, address ) { (address pairAddress, address token0, address token1) = orders.getPairInfo(pairId); (address tokenIn, address tokenOut) = pairInversed ? (token1, token0) : (token0, token1); return (pairAddress, tokenIn, tokenOut); } function _forceEtherTransfer(address to, uint256 amount) internal { IWETH(tokenShares.weth).withdraw(amount); (bool success, ) = to.call{ value: amount, gas: orders.transferGasCosts[address(0)] }(''); if (!success) { tokenShares.onUnwrapFailed(to, amount); } } function performRefund( Orders.OrderType orderType, uint256 validAfterTimestamp, uint256 orderId, bool shouldRefundEth ) internal { require(orderType != Orders.OrderType.Empty, 'TD41'); bool canOwnerRefund = validAfterTimestamp.add(365 days) < block.timestamp; if (orderType == Orders.OrderType.Deposit) { (Orders.DepositOrder memory depositOrder, , ) = orders.getDepositOrder(orderId); (, address token0, address token1) = orders.getPairInfo(depositOrder.pairId); address to = canOwnerRefund ? owner : depositOrder.to; require( refundTokens(to, token0, depositOrder.share0, token1, depositOrder.share1, depositOrder.unwrap), 'TD14' ); if (shouldRefundEth) { require(refundEth(payable(to), depositOrder.gasPrice.mul(depositOrder.gasLimit)), 'TD40'); } } else if (orderType == Orders.OrderType.Withdraw) { Orders.WithdrawOrder memory withdrawOrder = orders.getWithdrawOrder(orderId); (address pair, , ) = orders.getPairInfo(withdrawOrder.pairId); address to = canOwnerRefund ? owner : withdrawOrder.to; require(Orders.refundLiquidity(pair, to, withdrawOrder.liquidity, this._refundLiquidity.selector), 'TD14'); if (shouldRefundEth) { require(refundEth(payable(to), withdrawOrder.gasPrice.mul(withdrawOrder.gasLimit)), 'TD40'); } } else if (orderType == Orders.OrderType.Sell) { (Orders.SellOrder memory sellOrder, ) = orders.getSellOrder(orderId); (, address token0, address token1) = orders.getPairInfo(sellOrder.pairId); address to = canOwnerRefund ? owner : sellOrder.to; require(refundToken(sellOrder.inverse ? token1 : token0, to, sellOrder.shareIn, sellOrder.unwrap), 'TD14'); if (shouldRefundEth) { require(refundEth(payable(to), sellOrder.gasPrice.mul(sellOrder.gasLimit)), 'TD40'); } } else if (orderType == Orders.OrderType.Buy) { (Orders.BuyOrder memory buyOrder, ) = orders.getBuyOrder(orderId); (, address token0, address token1) = orders.getPairInfo(buyOrder.pairId); address to = canOwnerRefund ? owner : buyOrder.to; require(refundToken(buyOrder.inverse ? token1 : token0, to, buyOrder.shareInMax, buyOrder.unwrap), 'TD14'); if (shouldRefundEth) { require(refundEth(payable(to), buyOrder.gasPrice.mul(buyOrder.gasLimit)), 'TD40'); } } orders.forgetOrder(orderId); } function retryRefund(uint256 orderId) external override lock { (Orders.OrderType orderType, uint256 validAfterTimestamp) = orders.getFailedOrderType(orderId); performRefund(orderType, validAfterTimestamp, orderId, false); } function cancelOrder(uint256 orderId) external override lock { require(orders.getOrderStatus(orderId) == Orders.OrderStatus.EnqueuedReady, 'TD52'); (Orders.OrderType orderType, uint256 validAfterTimestamp) = orders.getOrder(orderId); require(validAfterTimestamp.sub(orders.delay).add(ORDER_CANCEL_TIME) < block.timestamp, 'TD1C'); orders.canceled[orderId] = true; performRefund(orderType, validAfterTimestamp, orderId, true); } function encodePriceInfo( address pair, uint256 priceAccumulator, uint32 priceTimestamp ) internal view returns (bytes memory data) { uint256 price = ITwapOracle(ITwapPair(pair).oracle()).getAveragePrice(priceAccumulator, priceTimestamp); // Pack everything as 32 bytes / uint256 to simplify decoding data = abi.encode(price); } receive() external payable {} }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; pragma abicoder v2; import '../libraries/Orders.sol'; interface ITwapDelay { event OrderExecuted(uint256 indexed id, bool indexed success, bytes data, uint256 gasSpent, uint256 ethRefunded); event RefundFailed(address indexed to, address indexed token, uint256 amount, bytes data); event EthRefund(address indexed to, bool indexed success, uint256 value); event OwnerSet(address owner); event BotSet(address bot, bool isBot); event DelaySet(uint256 delay); event MaxGasLimitSet(uint256 maxGasLimit); event GasPriceInertiaSet(uint256 gasPriceInertia); event MaxGasPriceImpactSet(uint256 maxGasPriceImpact); event TransferGasCostSet(address token, uint256 gasCost); event ToleranceSet(address pair, uint16 amount); event OrderDisabled(address pair, Orders.OrderType orderType, bool disabled); event UnwrapFailed(address to, uint256 amount); event Execute(address sender, uint256 n); function factory() external returns (address); function owner() external returns (address); function isBot(address bot) external returns (bool); function tolerance(address pair) external returns (uint16); function gasPriceInertia() external returns (uint256); function gasPrice() external returns (uint256); function maxGasPriceImpact() external returns (uint256); function maxGasLimit() external returns (uint256); function delay() external returns (uint32); function totalShares(address token) external returns (uint256); function weth() external returns (address); function getTransferGasCost(address token) external returns (uint256); function getDepositOrder(uint256 orderId) external returns (Orders.DepositOrder memory order); function getWithdrawOrder(uint256 orderId) external returns (Orders.WithdrawOrder memory order); function getSellOrder(uint256 orderId) external returns (Orders.SellOrder memory order); function getBuyOrder(uint256 orderId) external returns (Orders.BuyOrder memory order); function getDepositDisabled(address pair) external returns (bool); function getWithdrawDisabled(address pair) external returns (bool); function getBuyDisabled(address pair) external returns (bool); function getSellDisabled(address pair) external returns (bool); function getOrderStatus(uint256 orderId) external view returns (Orders.OrderStatus); function setOrderDisabled( address pair, Orders.OrderType orderType, bool disabled ) external payable; function setOwner(address _owner) external payable; function setBot(address _bot, bool _isBot) external payable; function setMaxGasLimit(uint256 _maxGasLimit) external payable; function setDelay(uint32 _delay) external payable; function setGasPriceInertia(uint256 _gasPriceInertia) external payable; function setMaxGasPriceImpact(uint256 _maxGasPriceImpact) external payable; function setTransferGasCost(address token, uint256 gasCost) external payable; function setTolerance(address pair, uint16 amount) external payable; function deposit(Orders.DepositParams memory depositParams) external payable returns (uint256 orderId); function withdraw(Orders.WithdrawParams memory withdrawParams) external payable returns (uint256 orderId); function sell(Orders.SellParams memory sellParams) external payable returns (uint256 orderId); function buy(Orders.BuyParams memory buyParams) external payable returns (uint256 orderId); function execute(uint256 n) external payable; function retryRefund(uint256 orderId) external; function cancelOrder(uint256 orderId) external; }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; interface IWETH { function deposit() external payable; function transfer(address to, uint256 value) external returns (bool); function withdraw(uint256) external; }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; import '../interfaces/IERC20.sol'; import '../interfaces/IWETH.sol'; import './SafeMath.sol'; import './TransferHelper.sol'; library TokenShares { using SafeMath for uint256; using TransferHelper for address; uint256 private constant PRECISION = 10**18; uint256 private constant TOLERANCE = 10**18 + 10**16; event UnwrapFailed(address to, uint256 amount); struct Data { mapping(address => uint256) totalShares; address weth; } function sharesToAmount( Data storage data, address token, uint256 share, uint256 amountLimit, address refundTo ) external returns (uint256) { if (share == 0) { return 0; } if (token == data.weth) { return share; } uint256 totalTokenShares = data.totalShares[token]; require(totalTokenShares >= share, 'TS3A'); uint256 balance = IERC20(token).balanceOf(address(this)); uint256 value = balance.mul(share).div(totalTokenShares); data.totalShares[token] = totalTokenShares.sub(share); if (amountLimit > 0) { uint256 amountLimitWithTolerance = amountLimit.mul(TOLERANCE).div(PRECISION); if (value > amountLimitWithTolerance) { TransferHelper.safeTransfer(token, refundTo, value.sub(amountLimitWithTolerance)); return amountLimitWithTolerance; } } return value; } function amountToShares( Data storage data, address token, uint256 amount, bool wrap ) external returns (uint256) { if (amount == 0) { return 0; } if (token == data.weth) { if (wrap) { require(msg.value >= amount, 'TS03'); IWETH(token).deposit{ value: amount }(); } else { token.safeTransferFrom(msg.sender, address(this), amount); } return amount; } else { uint256 balanceBefore = IERC20(token).balanceOf(address(this)); uint256 totalTokenShares = data.totalShares[token]; require(balanceBefore > 0 || totalTokenShares == 0, 'TS30'); if (totalTokenShares == 0) { totalTokenShares = balanceBefore; } token.safeTransferFrom(msg.sender, address(this), amount); uint256 balanceAfter = IERC20(token).balanceOf(address(this)); require(balanceAfter > balanceBefore, 'TS2C'); if (balanceBefore > 0) { uint256 newShares = totalTokenShares.mul(balanceAfter).div(balanceBefore); data.totalShares[token] = newShares; return newShares - totalTokenShares; } else { data.totalShares[token] = balanceAfter; return balanceAfter; } } } function onUnwrapFailed( Data storage data, address to, uint256 amount ) external { emit UnwrapFailed(to, amount); IWETH(data.weth).deposit{ value: amount }(); TransferHelper.safeTransfer(data.weth, to, amount); } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; import './ITwapERC20.sol'; import './IReserves.sol'; interface ITwapPair is ITwapERC20, IReserves { event Mint(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 liquidityOut, address indexed to); event Burn(address indexed sender, uint256 amount0Out, uint256 amount1Out, uint256 liquidityIn, address indexed to); event Swap( address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to ); event SetMintFee(uint256 fee); event SetBurnFee(uint256 fee); event SetSwapFee(uint256 fee); event SetOracle(address account); event SetTrader(address trader); function MINIMUM_LIQUIDITY() external pure returns (uint256); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function oracle() external view returns (address); function trader() external view returns (address); function mintFee() external view returns (uint256); function setMintFee(uint256 fee) external; function mint(address to) external returns (uint256 liquidity); function burnFee() external view returns (uint256); function setBurnFee(uint256 fee) external; function burn(address to) external returns (uint256 amount0, uint256 amount1); function swapFee() external view returns (uint256); function setSwapFee(uint256 fee) external; function setOracle(address account) external; function setTrader(address account) external; function collect(address to) external; function swap( uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data ) external; function sync() external; function initialize( address _token0, address _token1, address _oracle, address _trader ) external; function getSwapAmount0In(uint256 amount1Out, bytes calldata data) external view returns (uint256 swapAmount0In); function getSwapAmount1In(uint256 amount0Out, bytes calldata data) external view returns (uint256 swapAmount1In); function getSwapAmount0Out(uint256 amount1In, bytes calldata data) external view returns (uint256 swapAmount0Out); function getSwapAmount1Out(uint256 amount0In, bytes calldata data) external view returns (uint256 swapAmount1Out); function getDepositAmount0In(uint256 amount0, bytes calldata data) external view returns (uint256 depositAmount0In); function getDepositAmount1In(uint256 amount1, bytes calldata data) external view returns (uint256 depositAmount1In); }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; pragma abicoder v2; import './SafeMath.sol'; import '../libraries/Math.sol'; import '../interfaces/ITwapFactory.sol'; import '../interfaces/ITwapPair.sol'; import '../interfaces/ITwapOracle.sol'; import '../libraries/TokenShares.sol'; library Orders { using SafeMath for uint256; using TokenShares for TokenShares.Data; using TransferHelper for address; enum OrderType { Empty, Deposit, Withdraw, Sell, Buy } enum OrderStatus { NonExistent, EnqueuedWaiting, EnqueuedReady, ExecutedSucceeded, ExecutedFailed, Canceled } event MaxGasLimitSet(uint256 maxGasLimit); event GasPriceInertiaSet(uint256 gasPriceInertia); event MaxGasPriceImpactSet(uint256 maxGasPriceImpact); event TransferGasCostSet(address token, uint256 gasCost); event DepositEnqueued(uint256 indexed orderId, uint32 validAfterTimestamp, uint256 gasPrice); event WithdrawEnqueued(uint256 indexed orderId, uint32 validAfterTimestamp, uint256 gasPrice); event SellEnqueued(uint256 indexed orderId, uint32 validAfterTimestamp, uint256 gasPrice); event BuyEnqueued(uint256 indexed orderId, uint32 validAfterTimestamp, uint256 gasPrice); event OrderDisabled(address pair, Orders.OrderType orderType, bool disabled); event RefundFailed(address indexed to, address indexed token, uint256 amount, bytes data); uint8 private constant DEPOSIT_TYPE = 1; uint8 private constant WITHDRAW_TYPE = 2; uint8 private constant BUY_TYPE = 3; uint8 private constant BUY_INVERTED_TYPE = 4; uint8 private constant SELL_TYPE = 5; uint8 private constant SELL_INVERTED_TYPE = 6; uint8 private constant UNWRAP_NOT_FAILED = 0; uint8 private constant KEEP_NOT_FAILED = 1; uint8 private constant UNWRAP_FAILED = 2; uint8 private constant KEEP_FAILED = 3; uint256 private constant ETHER_TRANSFER_COST = 2600 + 1504; // EIP-2929 acct access cost + Gnosis Safe receive ETH cost uint256 private constant BUFFER_COST = 10000; uint256 private constant ORDER_EXECUTED_EVENT_COST = 3700; uint256 private constant EXECUTE_PREPARATION_COST = 55000; // dequeue + getPair in execute uint256 public constant ETHER_TRANSFER_CALL_COST = 10000; uint256 public constant PAIR_TRANSFER_COST = 55000; uint256 public constant REFUND_BASE_COST = 2 * ETHER_TRANSFER_COST + BUFFER_COST + ORDER_EXECUTED_EVENT_COST; uint256 public constant ORDER_BASE_COST = EXECUTE_PREPARATION_COST + REFUND_BASE_COST; // Masks used for setting order disabled // Different bits represent different order types uint8 private constant DEPOSIT_MASK = uint8(1 << uint8(OrderType.Deposit)); // 00000010 uint8 private constant WITHDRAW_MASK = uint8(1 << uint8(OrderType.Withdraw)); // 00000100 uint8 private constant SELL_MASK = uint8(1 << uint8(OrderType.Sell)); // 00001000 uint8 private constant BUY_MASK = uint8(1 << uint8(OrderType.Buy)); // 00010000 struct PairInfo { address pair; address token0; address token1; } struct Data { uint32 delay; uint256 newestOrderId; uint256 lastProcessedOrderId; mapping(uint256 => StoredOrder) orderQueue; address factory; uint256 maxGasLimit; uint256 gasPrice; uint256 gasPriceInertia; uint256 maxGasPriceImpact; mapping(uint32 => PairInfo) pairs; mapping(address => uint256) transferGasCosts; mapping(uint256 => bool) canceled; // Bit on specific positions indicates whether order type is disabled (1) or enabled (0) on specific pair mapping(address => uint8) orderDisabled; } struct StoredOrder { // slot 0 uint8 orderType; uint32 validAfterTimestamp; uint8 unwrapAndFailure; uint32 timestamp; uint32 gasLimit; uint32 gasPrice; uint112 liquidity; // slot 1 uint112 value0; uint112 value1; uint32 pairId; // slot2 address to; uint32 minSwapPrice; uint32 maxSwapPrice; bool swap; // slot3 uint256 priceAccumulator; // slot4 uint112 amountLimit0; uint112 amountLimit1; } struct DepositOrder { uint32 pairId; uint256 share0; uint256 share1; uint256 minSwapPrice; uint256 maxSwapPrice; bool unwrap; bool swap; address to; uint256 gasPrice; uint256 gasLimit; uint32 validAfterTimestamp; uint256 priceAccumulator; uint32 timestamp; } struct WithdrawOrder { uint32 pairId; uint256 liquidity; uint256 amount0Min; uint256 amount1Min; bool unwrap; address to; uint256 gasPrice; uint256 gasLimit; uint32 validAfterTimestamp; } struct SellOrder { uint32 pairId; bool inverse; uint256 shareIn; uint256 amountOutMin; bool unwrap; address to; uint256 gasPrice; uint256 gasLimit; uint32 validAfterTimestamp; uint256 priceAccumulator; uint32 timestamp; } struct BuyOrder { uint32 pairId; bool inverse; uint256 shareInMax; uint256 amountOut; bool unwrap; address to; uint256 gasPrice; uint256 gasLimit; uint32 validAfterTimestamp; uint256 priceAccumulator; uint32 timestamp; } function decodeType(uint256 internalType) internal pure returns (OrderType orderType) { if (internalType == DEPOSIT_TYPE) { orderType = OrderType.Deposit; } else if (internalType == WITHDRAW_TYPE) { orderType = OrderType.Withdraw; } else if (internalType == BUY_TYPE) { orderType = OrderType.Buy; } else if (internalType == BUY_INVERTED_TYPE) { orderType = OrderType.Buy; } else if (internalType == SELL_TYPE) { orderType = OrderType.Sell; } else if (internalType == SELL_INVERTED_TYPE) { orderType = OrderType.Sell; } else { orderType = OrderType.Empty; } } function getOrder(Data storage data, uint256 orderId) internal view returns (OrderType orderType, uint32 validAfterTimestamp) { StoredOrder storage order = data.orderQueue[orderId]; validAfterTimestamp = order.validAfterTimestamp; orderType = decodeType(order.orderType); } function getOrderStatus(Data storage data, uint256 orderId) internal view returns (OrderStatus orderStatus) { if (orderId > data.newestOrderId) { return OrderStatus.NonExistent; } if (data.canceled[orderId]) { return OrderStatus.Canceled; } if (isRefundFailed(data, orderId)) { return OrderStatus.ExecutedFailed; } (OrderType orderType, uint32 validAfterTimestamp) = getOrder(data, orderId); if (orderType == OrderType.Empty) { return OrderStatus.ExecutedSucceeded; } if (validAfterTimestamp >= block.timestamp) { return OrderStatus.EnqueuedWaiting; } return OrderStatus.EnqueuedReady; } function getPair( Data storage data, address tokenA, address tokenB ) internal returns ( address pair, uint32 pairId, bool inverted ) { inverted = tokenA > tokenB; (address token0, address token1) = inverted ? (tokenB, tokenA) : (tokenA, tokenB); pair = ITwapFactory(data.factory).getPair(token0, token1); require(pair != address(0), 'OS17'); pairId = uint32(bytes4(keccak256(abi.encodePacked(pair)))); if (data.pairs[pairId].pair == address(0)) { data.pairs[pairId] = PairInfo(pair, token0, token1); } } function getPairInfo(Data storage data, uint32 pairId) internal view returns ( address pair, address token0, address token1 ) { PairInfo storage info = data.pairs[pairId]; pair = info.pair; token0 = info.token0; token1 = info.token1; } function getDepositDisabled(Data storage data, address pair) internal view returns (bool) { return data.orderDisabled[pair] & DEPOSIT_MASK != 0; } function getWithdrawDisabled(Data storage data, address pair) internal view returns (bool) { return data.orderDisabled[pair] & WITHDRAW_MASK != 0; } function getSellDisabled(Data storage data, address pair) internal view returns (bool) { return data.orderDisabled[pair] & SELL_MASK != 0; } function getBuyDisabled(Data storage data, address pair) internal view returns (bool) { return data.orderDisabled[pair] & BUY_MASK != 0; } function getDepositOrder(Data storage data, uint256 index) public view returns ( DepositOrder memory order, uint256 amountLimit0, uint256 amountLimit1 ) { StoredOrder memory stored = data.orderQueue[index]; require(stored.orderType == DEPOSIT_TYPE, 'OS32'); order.pairId = stored.pairId; order.share0 = stored.value0; order.share1 = stored.value1; order.minSwapPrice = float32ToUint(stored.minSwapPrice); order.maxSwapPrice = float32ToUint(stored.maxSwapPrice); order.unwrap = getUnwrap(stored.unwrapAndFailure); order.swap = stored.swap; order.to = stored.to; order.gasPrice = uint32ToGasPrice(stored.gasPrice); order.gasLimit = stored.gasLimit; order.validAfterTimestamp = stored.validAfterTimestamp; order.priceAccumulator = stored.priceAccumulator; order.timestamp = stored.timestamp; amountLimit0 = stored.amountLimit0; amountLimit1 = stored.amountLimit1; } function getWithdrawOrder(Data storage data, uint256 index) public view returns (WithdrawOrder memory order) { StoredOrder memory stored = data.orderQueue[index]; require(stored.orderType == WITHDRAW_TYPE, 'OS32'); order.pairId = stored.pairId; order.liquidity = stored.liquidity; order.amount0Min = stored.value0; order.amount1Min = stored.value1; order.unwrap = getUnwrap(stored.unwrapAndFailure); order.to = stored.to; order.gasPrice = uint32ToGasPrice(stored.gasPrice); order.gasLimit = stored.gasLimit; order.validAfterTimestamp = stored.validAfterTimestamp; } function getSellOrder(Data storage data, uint256 index) public view returns (SellOrder memory order, uint256 amountLimit) { StoredOrder memory stored = data.orderQueue[index]; require(stored.orderType == SELL_TYPE || stored.orderType == SELL_INVERTED_TYPE, 'OS32'); order.pairId = stored.pairId; order.inverse = stored.orderType == SELL_INVERTED_TYPE; order.shareIn = stored.value0; order.amountOutMin = stored.value1; order.unwrap = getUnwrap(stored.unwrapAndFailure); order.to = stored.to; order.gasPrice = uint32ToGasPrice(stored.gasPrice); order.gasLimit = stored.gasLimit; order.validAfterTimestamp = stored.validAfterTimestamp; order.priceAccumulator = stored.priceAccumulator; order.timestamp = stored.timestamp; amountLimit = stored.amountLimit0; } function getBuyOrder(Data storage data, uint256 index) public view returns (BuyOrder memory order, uint256 amountLimit) { StoredOrder memory stored = data.orderQueue[index]; require(stored.orderType == BUY_TYPE || stored.orderType == BUY_INVERTED_TYPE, 'OS32'); order.pairId = stored.pairId; order.inverse = stored.orderType == BUY_INVERTED_TYPE; order.shareInMax = stored.value0; order.amountOut = stored.value1; order.unwrap = getUnwrap(stored.unwrapAndFailure); order.to = stored.to; order.gasPrice = uint32ToGasPrice(stored.gasPrice); order.gasLimit = stored.gasLimit; order.validAfterTimestamp = stored.validAfterTimestamp; order.timestamp = stored.timestamp; order.priceAccumulator = stored.priceAccumulator; amountLimit = stored.amountLimit0; } function getFailedOrderType(Data storage data, uint256 orderId) internal view returns (OrderType orderType, uint32 validAfterTimestamp) { require(isRefundFailed(data, orderId), 'OS21'); (orderType, validAfterTimestamp) = getOrder(data, orderId); } function getUnwrap(uint8 unwrapAndFailure) private pure returns (bool) { return unwrapAndFailure == UNWRAP_FAILED || unwrapAndFailure == UNWRAP_NOT_FAILED; } function getUnwrapAndFailure(bool unwrap) private pure returns (uint8) { return unwrap ? UNWRAP_NOT_FAILED : KEEP_NOT_FAILED; } function timestampToUint32(uint256 timestamp) private pure returns (uint32 timestamp32) { if (timestamp == type(uint256).max) { return type(uint32).max; } timestamp32 = timestamp.toUint32(); } function gasPriceToUint32(uint256 gasPrice) private pure returns (uint32 gasPrice32) { require((gasPrice / 1e6) * 1e6 == gasPrice, 'OS3C'); gasPrice32 = (gasPrice / 1e6).toUint32(); } function uint32ToGasPrice(uint32 gasPrice32) public pure returns (uint256 gasPrice) { gasPrice = uint256(gasPrice32) * 1e6; } function uintToFloat32(uint256 number) internal pure returns (uint32 float32) { // Number is encoded on 4 bytes. 3 bytes for mantissa and 1 for exponent. // If the number fits in the mantissa we set the exponent to zero and return. if (number < 1 << 24) { return uint32(number << 8); } // We find the exponent by counting the number of trailing zeroes. // Simultaneously we remove those zeroes from the number. uint32 exponent; for (; exponent < 256 - 24; ++exponent) { // Last bit is one. if (number & 1 == 1) { break; } number = number >> 1; } // The number must fit in the mantissa. require(number < 1 << 24, 'OS1A'); // Set the first three bytes to the number and the fourth to the exponent. float32 = uint32(number << 8) | exponent; } function float32ToUint(uint32 float32) internal pure returns (uint256 number) { // Number is encoded on 4 bytes. 3 bytes for mantissa and 1 for exponent. // We get the exponent by extracting the last byte. uint256 exponent = float32 & 0xFF; // Sanity check. Only triggered for values not encoded with uintToFloat32. require(exponent <= 256 - 24, 'OS1B'); // We get the mantissa by extracting the first three bytes and removing the fourth. uint256 mantissa = (float32 & 0xFFFFFF00) >> 8; // We add exponent number zeroes after the mantissa. number = mantissa << exponent; } function setOrderDisabled( Data storage data, address pair, Orders.OrderType orderType, bool disabled ) external { require(orderType != Orders.OrderType.Empty, 'OS32'); uint8 currentSettings = data.orderDisabled[pair]; // zeros with 1 bit set at position specified by orderType uint8 mask = uint8(1 << uint8(orderType)); // set/unset a bit accordingly to 'disabled' value if (disabled) { // OR operation to disable order // e.g. for disable DEPOSIT // currentSettings = 00010100 (BUY and WITHDRAW disabled) // mask for DEPOSIT = 00000010 // the result of OR = 00010110 currentSettings = currentSettings | mask; } else { // AND operation with a mask negation to enable order // e.g. for enable DEPOSIT // currentSettings = 00010100 (BUY and WITHDRAW disabled) // 0xff = 11111111 // mask for Deposit = 00000010 // mask negation = 11111101 // the result of AND = 00010100 currentSettings = currentSettings & (mask ^ 0xff); } require(currentSettings != data.orderDisabled[pair], 'OS01'); data.orderDisabled[pair] = currentSettings; emit OrderDisabled(pair, orderType, disabled); } function enqueueDepositOrder( Data storage data, DepositOrder memory depositOrder, uint256 amountIn0, uint256 amountIn1 ) internal { ++data.newestOrderId; emit DepositEnqueued(data.newestOrderId, depositOrder.validAfterTimestamp, depositOrder.gasPrice); data.orderQueue[data.newestOrderId] = StoredOrder( DEPOSIT_TYPE, depositOrder.validAfterTimestamp, getUnwrapAndFailure(depositOrder.unwrap), depositOrder.timestamp, depositOrder.gasLimit.toUint32(), gasPriceToUint32(depositOrder.gasPrice), 0, // liquidity depositOrder.share0.toUint112(), depositOrder.share1.toUint112(), depositOrder.pairId, depositOrder.to, uintToFloat32(depositOrder.minSwapPrice), uintToFloat32(depositOrder.maxSwapPrice), depositOrder.swap, depositOrder.priceAccumulator, amountIn0.toUint112(), amountIn1.toUint112() ); } function enqueueWithdrawOrder(Data storage data, WithdrawOrder memory withdrawOrder) internal { ++data.newestOrderId; emit WithdrawEnqueued(data.newestOrderId, withdrawOrder.validAfterTimestamp, withdrawOrder.gasPrice); data.orderQueue[data.newestOrderId] = StoredOrder( WITHDRAW_TYPE, withdrawOrder.validAfterTimestamp, getUnwrapAndFailure(withdrawOrder.unwrap), 0, // timestamp withdrawOrder.gasLimit.toUint32(), gasPriceToUint32(withdrawOrder.gasPrice), withdrawOrder.liquidity.toUint112(), withdrawOrder.amount0Min.toUint112(), withdrawOrder.amount1Min.toUint112(), withdrawOrder.pairId, withdrawOrder.to, 0, // minSwapPrice 0, // maxSwapPrice false, // swap 0, // priceAccumulator 0, // amountLimit0 0 // amountLimit1 ); } function enqueueSellOrder( Data storage data, SellOrder memory sellOrder, uint256 amountIn ) internal { ++data.newestOrderId; emit SellEnqueued(data.newestOrderId, sellOrder.validAfterTimestamp, sellOrder.gasPrice); data.orderQueue[data.newestOrderId] = StoredOrder( sellOrder.inverse ? SELL_INVERTED_TYPE : SELL_TYPE, sellOrder.validAfterTimestamp, getUnwrapAndFailure(sellOrder.unwrap), sellOrder.timestamp, sellOrder.gasLimit.toUint32(), gasPriceToUint32(sellOrder.gasPrice), 0, // liquidity sellOrder.shareIn.toUint112(), sellOrder.amountOutMin.toUint112(), sellOrder.pairId, sellOrder.to, 0, // minSwapPrice 0, // maxSwapPrice false, // swap sellOrder.priceAccumulator, amountIn.toUint112(), 0 // amountLimit1 ); } function enqueueBuyOrder( Data storage data, BuyOrder memory buyOrder, uint256 amountInMax ) internal { ++data.newestOrderId; emit BuyEnqueued(data.newestOrderId, buyOrder.validAfterTimestamp, buyOrder.gasPrice); data.orderQueue[data.newestOrderId] = StoredOrder( buyOrder.inverse ? BUY_INVERTED_TYPE : BUY_TYPE, buyOrder.validAfterTimestamp, getUnwrapAndFailure(buyOrder.unwrap), buyOrder.timestamp, buyOrder.gasLimit.toUint32(), gasPriceToUint32(buyOrder.gasPrice), 0, // liquidity buyOrder.shareInMax.toUint112(), buyOrder.amountOut.toUint112(), buyOrder.pairId, buyOrder.to, 0, // minSwapPrice 0, // maxSwapPrice false, // swap buyOrder.priceAccumulator, amountInMax.toUint112(), 0 // amountLimit1 ); } function isRefundFailed(Data storage data, uint256 index) internal view returns (bool) { uint8 unwrapAndFailure = data.orderQueue[index].unwrapAndFailure; return unwrapAndFailure == UNWRAP_FAILED || unwrapAndFailure == KEEP_FAILED; } function markRefundFailed(Data storage data) internal { StoredOrder storage stored = data.orderQueue[data.lastProcessedOrderId]; stored.unwrapAndFailure = stored.unwrapAndFailure == UNWRAP_NOT_FAILED ? UNWRAP_FAILED : KEEP_FAILED; } struct DepositParams { address token0; address token1; uint256 amount0; uint256 amount1; uint256 minSwapPrice; uint256 maxSwapPrice; bool wrap; bool swap; address to; uint256 gasLimit; uint32 submitDeadline; } function deposit( Data storage data, DepositParams calldata depositParams, TokenShares.Data storage tokenShares ) external { { // scope for checks, avoids stack too deep errors uint256 token0TransferCost = data.transferGasCosts[depositParams.token0]; uint256 token1TransferCost = data.transferGasCosts[depositParams.token1]; require(token0TransferCost != 0 && token1TransferCost != 0, 'OS0F'); checkOrderParams( data, depositParams.to, depositParams.gasLimit, depositParams.submitDeadline, ORDER_BASE_COST.add(token0TransferCost).add(token1TransferCost) ); } require(depositParams.amount0 != 0 || depositParams.amount1 != 0, 'OS25'); (address pairAddress, uint32 pairId, bool inverted) = getPair(data, depositParams.token0, depositParams.token1); require(!getDepositDisabled(data, pairAddress), 'OS46'); { // scope for value, avoids stack too deep errors uint256 value = msg.value; // allocate gas refund if (depositParams.wrap) { if (depositParams.token0 == tokenShares.weth) { value = msg.value.sub(depositParams.amount0, 'OS1E'); } else if (depositParams.token1 == tokenShares.weth) { value = msg.value.sub(depositParams.amount1, 'OS1E'); } } allocateGasRefund(data, value, depositParams.gasLimit); } uint256 shares0 = tokenShares.amountToShares( inverted ? depositParams.token1 : depositParams.token0, inverted ? depositParams.amount1 : depositParams.amount0, depositParams.wrap ); uint256 shares1 = tokenShares.amountToShares( inverted ? depositParams.token0 : depositParams.token1, inverted ? depositParams.amount0 : depositParams.amount1, depositParams.wrap ); (uint256 priceAccumulator, uint32 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo(); enqueueDepositOrder( data, DepositOrder( pairId, shares0, shares1, depositParams.minSwapPrice, depositParams.maxSwapPrice, depositParams.wrap, depositParams.swap, depositParams.to, data.gasPrice, depositParams.gasLimit, timestamp + data.delay, // validAfterTimestamp priceAccumulator, timestamp ), inverted ? depositParams.amount1 : depositParams.amount0, inverted ? depositParams.amount0 : depositParams.amount1 ); } struct WithdrawParams { address token0; address token1; uint256 liquidity; uint256 amount0Min; uint256 amount1Min; bool unwrap; address to; uint256 gasLimit; uint32 submitDeadline; } function withdraw(Data storage data, WithdrawParams calldata withdrawParams) external { (address pair, uint32 pairId, bool inverted) = getPair(data, withdrawParams.token0, withdrawParams.token1); require(!getWithdrawDisabled(data, pair), 'OS0A'); checkOrderParams( data, withdrawParams.to, withdrawParams.gasLimit, withdrawParams.submitDeadline, ORDER_BASE_COST.add(PAIR_TRANSFER_COST) ); require(withdrawParams.liquidity != 0, 'OS22'); allocateGasRefund(data, msg.value, withdrawParams.gasLimit); pair.safeTransferFrom(msg.sender, address(this), withdrawParams.liquidity); enqueueWithdrawOrder( data, WithdrawOrder( pairId, withdrawParams.liquidity, inverted ? withdrawParams.amount1Min : withdrawParams.amount0Min, inverted ? withdrawParams.amount0Min : withdrawParams.amount1Min, withdrawParams.unwrap, withdrawParams.to, data.gasPrice, withdrawParams.gasLimit, timestampToUint32(block.timestamp) + data.delay ) ); } struct SellParams { address tokenIn; address tokenOut; uint256 amountIn; uint256 amountOutMin; bool wrapUnwrap; address to; uint256 gasLimit; uint32 submitDeadline; } function sell( Data storage data, SellParams calldata sellParams, TokenShares.Data storage tokenShares ) external { uint256 tokenTransferCost = data.transferGasCosts[sellParams.tokenIn]; require(tokenTransferCost != 0, 'OS0F'); checkOrderParams( data, sellParams.to, sellParams.gasLimit, sellParams.submitDeadline, ORDER_BASE_COST.add(tokenTransferCost) ); require(sellParams.amountIn != 0, 'OS24'); (address pairAddress, uint32 pairId, bool inverted) = getPair(data, sellParams.tokenIn, sellParams.tokenOut); require(!getSellDisabled(data, pairAddress), 'OS13'); uint256 value = msg.value; // allocate gas refund if (sellParams.tokenIn == tokenShares.weth && sellParams.wrapUnwrap) { value = msg.value.sub(sellParams.amountIn, 'OS1E'); } allocateGasRefund(data, value, sellParams.gasLimit); uint256 shares = tokenShares.amountToShares(sellParams.tokenIn, sellParams.amountIn, sellParams.wrapUnwrap); (uint256 priceAccumulator, uint32 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo(); enqueueSellOrder( data, SellOrder( pairId, inverted, shares, sellParams.amountOutMin, sellParams.wrapUnwrap, sellParams.to, data.gasPrice, sellParams.gasLimit, timestamp + data.delay, priceAccumulator, timestamp ), sellParams.amountIn ); } struct BuyParams { address tokenIn; address tokenOut; uint256 amountInMax; uint256 amountOut; bool wrapUnwrap; address to; uint256 gasLimit; uint32 submitDeadline; } function buy( Data storage data, BuyParams calldata buyParams, TokenShares.Data storage tokenShares ) external { uint256 tokenTransferCost = data.transferGasCosts[buyParams.tokenIn]; require(tokenTransferCost != 0, 'OS0F'); checkOrderParams( data, buyParams.to, buyParams.gasLimit, buyParams.submitDeadline, ORDER_BASE_COST.add(tokenTransferCost) ); require(buyParams.amountOut != 0, 'OS23'); (address pairAddress, uint32 pairId, bool inverted) = getPair(data, buyParams.tokenIn, buyParams.tokenOut); require(!getBuyDisabled(data, pairAddress), 'OS49'); uint256 value = msg.value; // allocate gas refund if (buyParams.tokenIn == tokenShares.weth && buyParams.wrapUnwrap) { value = msg.value.sub(buyParams.amountInMax, 'OS1E'); } allocateGasRefund(data, value, buyParams.gasLimit); uint256 shares = tokenShares.amountToShares(buyParams.tokenIn, buyParams.amountInMax, buyParams.wrapUnwrap); (uint256 priceAccumulator, uint32 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo(); enqueueBuyOrder( data, BuyOrder( pairId, inverted, shares, buyParams.amountOut, buyParams.wrapUnwrap, buyParams.to, data.gasPrice, buyParams.gasLimit, timestamp + data.delay, priceAccumulator, timestamp ), buyParams.amountInMax ); } function checkOrderParams( Data storage data, address to, uint256 gasLimit, uint32 submitDeadline, uint256 minGasLimit ) private view { require(submitDeadline >= block.timestamp, 'OS04'); require(gasLimit <= data.maxGasLimit, 'OS3E'); require(gasLimit >= minGasLimit, 'OS3D'); require(to != address(0), 'OS26'); } function allocateGasRefund( Data storage data, uint256 value, uint256 gasLimit ) private returns (uint256 futureFee) { futureFee = data.gasPrice.mul(gasLimit); require(value >= futureFee, 'OS1E'); if (value > futureFee) { TransferHelper.safeTransferETH(msg.sender, value.sub(futureFee), data.transferGasCosts[address(0)]); } } function updateGasPrice(Data storage data, uint256 gasUsed) external { uint256 scale = Math.min(gasUsed, data.maxGasPriceImpact); uint256 updated = data.gasPrice.mul(data.gasPriceInertia.sub(scale)).add(tx.gasprice.mul(scale)).div( data.gasPriceInertia ); // we lower the precision for gas savings in order queue data.gasPrice = updated - (updated % 1e6); } function setMaxGasLimit(Data storage data, uint256 _maxGasLimit) external { require(_maxGasLimit != data.maxGasLimit, 'OS01'); require(_maxGasLimit <= 10000000, 'OS2B'); data.maxGasLimit = _maxGasLimit; emit MaxGasLimitSet(_maxGasLimit); } function setGasPriceInertia(Data storage data, uint256 _gasPriceInertia) external { require(_gasPriceInertia != data.gasPriceInertia, 'OS01'); require(_gasPriceInertia >= 1, 'OS35'); data.gasPriceInertia = _gasPriceInertia; emit GasPriceInertiaSet(_gasPriceInertia); } function setMaxGasPriceImpact(Data storage data, uint256 _maxGasPriceImpact) external { require(_maxGasPriceImpact != data.maxGasPriceImpact, 'OS01'); require(_maxGasPriceImpact <= data.gasPriceInertia, 'OS33'); data.maxGasPriceImpact = _maxGasPriceImpact; emit MaxGasPriceImpactSet(_maxGasPriceImpact); } function setTransferGasCost( Data storage data, address token, uint256 gasCost ) external { require(gasCost != data.transferGasCosts[token], 'OS01'); data.transferGasCosts[token] = gasCost; emit TransferGasCostSet(token, gasCost); } function refundLiquidity( address pair, address to, uint256 liquidity, bytes4 selector ) internal returns (bool) { if (liquidity == 0) { return true; } (bool success, bytes memory data) = address(this).call{ gas: PAIR_TRANSFER_COST }( abi.encodeWithSelector(selector, pair, to, liquidity, false) ); if (!success) { emit RefundFailed(to, pair, liquidity, data); } return success; } function getNextOrder(Data storage data) internal view returns (OrderType orderType, uint256 validAfterTimestamp) { return getOrder(data, data.lastProcessedOrderId + 1); } function dequeueCanceledOrder(Data storage data) internal { ++data.lastProcessedOrderId; } function dequeueDepositOrder(Data storage data) external returns ( DepositOrder memory order, uint256 amountLimit0, uint256 amountLimit1 ) { ++data.lastProcessedOrderId; (order, amountLimit0, amountLimit1) = getDepositOrder(data, data.lastProcessedOrderId); } function dequeueWithdrawOrder(Data storage data) external returns (WithdrawOrder memory order) { ++data.lastProcessedOrderId; order = getWithdrawOrder(data, data.lastProcessedOrderId); } function dequeueSellOrder(Data storage data) external returns (SellOrder memory order, uint256 amountLimit) { ++data.lastProcessedOrderId; (order, amountLimit) = getSellOrder(data, data.lastProcessedOrderId); } function dequeueBuyOrder(Data storage data) external returns (BuyOrder memory order, uint256 amountLimit) { ++data.lastProcessedOrderId; (order, amountLimit) = getBuyOrder(data, data.lastProcessedOrderId); } function forgetOrder(Data storage data, uint256 orderId) internal { delete data.orderQueue[orderId]; } function forgetLastProcessedOrder(Data storage data) internal { delete data.orderQueue[data.lastProcessedOrderId]; } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) library SafeMath { int256 private constant _INT256_MIN = -2**255; function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x, 'SM4E'); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { z = sub(x, y, 'SM12'); } function sub( uint256 x, uint256 y, string memory message ) internal pure returns (uint256 z) { require((z = x - y) <= x, message); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x, 'SM2A'); } function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, 'SM43'); return a / b; } function ceil_div(uint256 a, uint256 b) internal pure returns (uint256 c) { c = div(a, b); if (a != mul(b, c)) { return add(c, 1); } } function toUint32(uint256 n) internal pure returns (uint32) { require(n <= type(uint32).max, 'SM50'); return uint32(n); } function toUint112(uint256 n) internal pure returns (uint112) { require(n <= type(uint112).max, 'SM51'); return uint112(n); } function toInt256(uint256 unsigned) internal pure returns (int256 signed) { require(unsigned <= uint256(type(int256).max), 'SM34'); signed = int256(unsigned); } // int256 function add(int256 a, int256 b) internal pure returns (int256 c) { c = a + b; require((b >= 0 && c >= a) || (b < 0 && c < a), 'SM4D'); } function sub(int256 a, int256 b) internal pure returns (int256 c) { c = a - b; require((b >= 0 && c <= a) || (b < 0 && c > a), 'SM11'); } function mul(int256 a, int256 b) internal pure returns (int256 c) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } require(!(a == -1 && b == _INT256_MIN), 'SM29'); c = a * b; require(c / a == b, 'SM29'); } function div(int256 a, int256 b) internal pure returns (int256) { require(b != 0, 'SM43'); require(!(b == -1 && a == _INT256_MIN), 'SM42'); return a / b; } function neg_floor_div(int256 a, int256 b) internal pure returns (int256 c) { c = div(a, b); if ((a < 0 && b > 0) || (a >= 0 && b < 0)) { if (a != mul(b, c)) { c = sub(c, 1); } } } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; import './TransferHelper.sol'; import './SafeMath.sol'; import './Math.sol'; import '../interfaces/ITwapPair.sol'; import '../interfaces/ITwapOracle.sol'; library AddLiquidity { using SafeMath for uint256; function addLiquidity( address pair, uint256 amount0Desired, uint256 amount1Desired ) internal view returns ( uint256 amount0, uint256 amount1, uint256 swapToken ) { if (amount0Desired == 0 || amount1Desired == 0) { if (amount0Desired > 0) { swapToken = 1; } else if (amount1Desired > 0) { swapToken = 2; } return (0, 0, swapToken); } (uint256 reserve0, uint256 reserve1) = ITwapPair(pair).getReserves(); if (reserve0 == 0 && reserve1 == 0) { (amount0, amount1) = (amount0Desired, amount1Desired); } else { require(reserve0 > 0 && reserve1 > 0, 'AL07'); uint256 amount1Optimal = amount0Desired.mul(reserve1) / reserve0; if (amount1Optimal <= amount1Desired) { swapToken = 2; (amount0, amount1) = (amount0Desired, amount1Optimal); } else { uint256 amount0Optimal = amount1Desired.mul(reserve0) / reserve1; assert(amount0Optimal <= amount0Desired); swapToken = 1; (amount0, amount1) = (amount0Optimal, amount1Desired); } uint256 totalSupply = ITwapPair(pair).totalSupply(); uint256 liquidityOut = Math.min(amount0.mul(totalSupply) / reserve0, amount1.mul(totalSupply) / reserve1); if (liquidityOut == 0) { amount0 = 0; amount1 = 0; } } } function addLiquidityAndMint( address pair, address to, address token0, address token1, uint256 amount0Desired, uint256 amount1Desired ) external returns ( uint256 amount0Left, uint256 amount1Left, uint256 swapToken ) { uint256 amount0; uint256 amount1; (amount0, amount1, swapToken) = addLiquidity(pair, amount0Desired, amount1Desired); if (amount0 == 0 || amount1 == 0) { return (amount0Desired, amount1Desired, swapToken); } TransferHelper.safeTransfer(token0, pair, amount0); TransferHelper.safeTransfer(token1, pair, amount1); ITwapPair(pair).mint(to); amount0Left = amount0Desired.sub(amount0); amount1Left = amount1Desired.sub(amount1); } function swapDeposit0( address pair, address token0, uint256 amount0, uint256 minSwapPrice, uint16 tolerance, bytes calldata data ) external returns (uint256 amount0Left, uint256 amount1Left) { uint256 amount0In = ITwapPair(pair).getDepositAmount0In(amount0, data); amount1Left = ITwapPair(pair).getSwapAmount1Out(amount0In, data).sub(tolerance); if (amount1Left == 0) { return (amount0, amount1Left); } uint256 price = getPrice(amount0In, amount1Left, pair); require(minSwapPrice == 0 || price >= minSwapPrice, 'AL15'); TransferHelper.safeTransfer(token0, pair, amount0In); ITwapPair(pair).swap(0, amount1Left, address(this), data); amount0Left = amount0.sub(amount0In); } function swapDeposit1( address pair, address token1, uint256 amount1, uint256 maxSwapPrice, uint16 tolerance, bytes calldata data ) external returns (uint256 amount0Left, uint256 amount1Left) { uint256 amount1In = ITwapPair(pair).getDepositAmount1In(amount1, data); amount0Left = ITwapPair(pair).getSwapAmount0Out(amount1In, data).sub(tolerance); if (amount0Left == 0) { return (amount0Left, amount1); } uint256 price = getPrice(amount0Left, amount1In, pair); require(maxSwapPrice == 0 || price <= maxSwapPrice, 'AL16'); TransferHelper.safeTransfer(token1, pair, amount1In); ITwapPair(pair).swap(amount0Left, 0, address(this), data); amount1Left = amount1.sub(amount1In); } function getPrice( uint256 amount0, uint256 amount1, address pair ) internal view returns (uint256) { ITwapOracle oracle = ITwapOracle(ITwapPair(pair).oracle()); return amount1.mul(uint256(oracle.decimalsConverter())).div(amount0); } function _refundDeposit( address to, address token0, address token1, uint256 amount0, uint256 amount1 ) internal { if (amount0 > 0) { TransferHelper.safeTransfer(token0, to, amount0); } if (amount1 > 0) { TransferHelper.safeTransfer(token1, to, amount1); } } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; pragma abicoder v2; import '../interfaces/ITwapPair.sol'; import '../interfaces/IWETH.sol'; import './Orders.sol'; library WithdrawHelper { using SafeMath for uint256; function _transferToken( uint256 balanceBefore, address token, address to ) internal { uint256 tokenAmount = IERC20(token).balanceOf(address(this)).sub(balanceBefore); TransferHelper.safeTransfer(token, to, tokenAmount); } function _unwrapWeth( uint256 ethAmount, address weth, address to, uint256 gasLimit ) internal returns (bool) { IWETH(weth).withdraw(ethAmount); (bool success, ) = to.call{ value: ethAmount, gas: gasLimit }(''); return success; } function withdrawAndUnwrap( address token0, address token1, address pair, address weth, address to, uint256 gasLimit ) external returns ( bool, uint256, uint256, uint256 ) { bool isToken0Weth = token0 == weth; address otherToken = isToken0Weth ? token1 : token0; uint256 balanceBefore = IERC20(otherToken).balanceOf(address(this)); (uint256 amount0, uint256 amount1) = ITwapPair(pair).burn(address(this)); _transferToken(balanceBefore, otherToken, to); bool success = _unwrapWeth(isToken0Weth ? amount0 : amount1, weth, to, gasLimit); return (success, isToken0Weth ? amount0 : amount1, amount0, amount1); } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; // a library for performing various math operations library Math { function min(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x < y ? x : y; } function max(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x > y ? x : y; } // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) function sqrt(uint256 y) internal pure returns (uint256 z) { if (y > 3) { z = y; uint256 x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; interface ITwapOracle { event OwnerSet(address owner); event UniswapPairSet(address uniswapPair); function decimalsConverter() external view returns (int256); function xDecimals() external view returns (uint8); function yDecimals() external view returns (uint8); function owner() external view returns (address); function uniswapPair() external view returns (address); function getPriceInfo() external view returns (uint256 priceAccumulator, uint32 priceTimestamp); function getSpotPrice() external view returns (uint256); function getAveragePrice(uint256 priceAccumulator, uint32 priceTimestamp) external view returns (uint256); function setOwner(address _owner) external; function setUniswapPair(address _uniswapPair) external; function tradeX( uint256 xAfter, uint256 xBefore, uint256 yBefore, bytes calldata data ) external view returns (uint256 yAfter); function tradeY( uint256 yAfter, uint256 yBefore, uint256 xBefore, bytes calldata data ) external view returns (uint256 xAfter); function depositTradeXIn( uint256 xLeft, uint256 xBefore, uint256 yBefore, bytes calldata data ) external view returns (uint256 xIn); function depositTradeYIn( uint256 yLeft, uint256 yBefore, uint256 xBefore, bytes calldata data ) external view returns (uint256 yIn); function getSwapAmount0Out( uint256 swapFee, uint256 amount1In, bytes calldata data ) external view returns (uint256 amount0Out); function getSwapAmount1Out( uint256 swapFee, uint256 amount0In, bytes calldata data ) external view returns (uint256 amount1Out); function getSwapAmountInMaxOut( bool inverse, uint256 swapFee, uint256 _amountOut, bytes calldata data ) external view returns (uint256 amountIn, uint256 amountOut); function getSwapAmountInMinOut( bool inverse, uint256 swapFee, uint256 _amountOut, bytes calldata data ) external view returns (uint256 amountIn, uint256 amountOut); }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; interface ITwapFactory { event PairCreated(address indexed token0, address indexed token1, address pair, uint256); event OwnerSet(address owner); function owner() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint256) external view returns (address pair); function allPairsLength() external view returns (uint256); function createPair( address tokenA, address tokenB, address oracle, address trader ) external returns (address pair); function setOwner(address) external; function setMintFee( address tokenA, address tokenB, uint256 fee ) external; function setBurnFee( address tokenA, address tokenB, uint256 fee ) external; function setSwapFee( address tokenA, address tokenB, uint256 fee ) external; function setOracle( address tokenA, address tokenB, address oracle ) external; function setTrader( address tokenA, address tokenB, address trader ) external; function collect( address tokenA, address tokenB, address to ) external; function withdraw( address tokenA, address tokenB, uint256 amount, address to ) external; }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; import './IERC20.sol'; interface ITwapERC20 is IERC20 { function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint256); function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; function increaseAllowance(address spender, uint256 addedValue) external returns (bool); function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; interface IReserves { function getReserves() external view returns (uint112 reserve0, uint112 reserve1); function getFees() external view returns (uint256 fee0, uint256 fee1); }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; interface IERC20 { event Approval(address indexed owner, address indexed spender, uint256 value); event Transfer(address indexed from, address indexed to, uint256 value); function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); function totalSupply() external view returns (uint256); function balanceOf(address owner) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 value) external returns (bool); function transfer(address to, uint256 value) external returns (bool); function transferFrom( address from, address to, uint256 value ) external returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false library TransferHelper { function safeApprove( address token, address to, uint256 value ) internal { // bytes4(keccak256(bytes('approve(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TH4B'); } function safeTransfer( address token, address to, uint256 value ) internal { // bytes4(keccak256(bytes('transfer(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TH05'); } function safeTransferFrom( address token, address from, address to, uint256 value ) internal { // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TH0E'); } function safeTransferETH( address to, uint256 value, uint256 gasLimit ) internal { (bool success, ) = to.call{ value: value, gas: gasLimit }(''); require(success, 'TH3F'); } function transferETH( address to, uint256 value, uint256 gasLimit ) internal returns (bool success) { (success, ) = to.call{ value: value, gas: gasLimit }(''); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": { "contracts/libraries/AddLiquidity.sol": { "AddLiquidity": "0x0ec2323adafbebc6c80257c7359692bcceb0b3f1" }, "contracts/libraries/Orders.sol": { "Orders": "0x9cb505f2b41aa426257ed2a0bba005fff0af9e9a" }, "contracts/libraries/TokenShares.sol": { "TokenShares": "0x412da11751b0a36d03b060890f4e41b7ce32971e" }, "contracts/libraries/WithdrawHelper.sol": { "WithdrawHelper": "0x6195015b38773f468dd43620dd5a64e9bb63c2e3" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_bot","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"bot","type":"address"},{"indexed":false,"internalType":"bool","name":"isBot","type":"bool"}],"name":"BotSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"DelaySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"EthRefund","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"n","type":"uint256"}],"name":"Execute","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"gasPriceInertia","type":"uint256"}],"name":"GasPriceInertiaSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxGasLimit","type":"uint256"}],"name":"MaxGasLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxGasPriceImpact","type":"uint256"}],"name":"MaxGasPriceImpactSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"indexed":false,"internalType":"bool","name":"disabled","type":"bool"}],"name":"OrderDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"gasSpent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ethRefunded","type":"uint256"}],"name":"OrderExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"OwnerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"RefundFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"uint16","name":"amount","type":"uint16"}],"name":"ToleranceSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"gasCost","type":"uint256"}],"name":"TransferGasCostSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"UnwrapFailed","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"bool","name":"inverse","type":"bool"},{"internalType":"uint256","name":"shareInMax","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.BuyOrder","name":"buyOrder","type":"tuple"},{"internalType":"uint256","name":"amountLimit","type":"uint256"}],"name":"_executeBuy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"uint256","name":"share0","type":"uint256"},{"internalType":"uint256","name":"share1","type":"uint256"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.DepositOrder","name":"depositOrder","type":"tuple"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"name":"_executeDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"bool","name":"inverse","type":"bool"},{"internalType":"uint256","name":"shareIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.SellOrder","name":"sellOrder","type":"tuple"},{"internalType":"uint256","name":"amountLimit","type":"uint256"}],"name":"_executeSell","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"}],"internalType":"struct Orders.WithdrawOrder","name":"withdrawOrder","type":"tuple"}],"name":"_executeWithdraw","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"name":"_refundLiquidity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"share","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"}],"name":"_refundToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"uint256","name":"share0","type":"uint256"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"share1","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"}],"name":"_refundTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"bool","name":"wrapUnwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.BuyParams","name":"buyParams","type":"tuple"}],"name":"buy","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delay","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"wrap","type":"bool"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.DepositParams","name":"depositParams","type":"tuple"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"n","type":"uint256"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasPriceInertia","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getBuyDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getBuyOrder","outputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"bool","name":"inverse","type":"bool"},{"internalType":"uint256","name":"shareInMax","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.BuyOrder","name":"order","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getDepositDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getDepositOrder","outputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"uint256","name":"share0","type":"uint256"},{"internalType":"uint256","name":"share1","type":"uint256"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.DepositOrder","name":"order","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getOrder","outputs":[{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getOrderStatus","outputs":[{"internalType":"enum Orders.OrderStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getSellDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getSellOrder","outputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"bool","name":"inverse","type":"bool"},{"internalType":"uint256","name":"shareIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.SellOrder","name":"order","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTransferGasCost","outputs":[{"internalType":"uint256","name":"gasCost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getWithdrawDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getWithdrawOrder","outputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"}],"internalType":"struct Orders.WithdrawOrder","name":"order","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isBot","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"isOrderCanceled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastProcessedOrderId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxGasLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxGasPriceImpact","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newestOrderId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"retryRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"wrapUnwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.SellParams","name":"sellParams","type":"tuple"}],"name":"sell","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_bot","type":"address"},{"internalType":"bool","name":"_isBot","type":"bool"}],"name":"setBot","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_delay","type":"uint32"}],"name":"setDelay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasPriceInertia","type":"uint256"}],"name":"setGasPriceInertia","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxGasLimit","type":"uint256"}],"name":"setMaxGasLimit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxGasPriceImpact","type":"uint256"}],"name":"setMaxGasPriceImpact","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"disabled","type":"bool"}],"name":"setOrderDisabled","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"},{"internalType":"uint16","name":"amount","type":"uint16"}],"name":"setTolerance","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"gasCost","type":"uint256"}],"name":"setTransferGasCost","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tolerance","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.WithdrawParams","name":"withdrawParams","type":"tuple"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620060c6380380620060c6833981016040819052620000349162000197565b600480546001600160a01b038086166001600160a01b031992831617909255600f80549091163317905581166000908152601060205260409020805460ff19166001179055620f42403a063a03600655600e80546001600160a01b0384166001600160a01b03199091161790556000805463ffffffff1916610708178155624c4b406005556301312d00600755620f424060085560405163b2456a0760e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a9163b2456a0791620001069190819061271090600401620001f4565b60006040518083038186803b1580156200011f57600080fd5b505af415801562000134573d6000803e3d6000fd5b505050507f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe233604051620001699190620001e0565b60405180910390a150505062000213565b80516001600160a01b03811681146200019257600080fd5b919050565b600080600060608486031215620001ac578283fd5b620001b7846200017a565b9250620001c7602085016200017a565b9150620001d7604085016200017a565b90509250925092565b6001600160a01b0391909116815260200190565b9283526001600160a01b03919091166020830152604082015260600190565b615ea380620002236000396000f3fe6080604052600436106102975760003560e01c80638da5cb5b1161015a578063c69cee72116100c1578063e5e7988e1161007a578063e5e7988e1461072f578063e6a0cc941461074f578063f16508f614610764578063fe0d94c114610777578063fe136a8e1461078a578063fe173b971461079d5761029e565b8063c69cee72146106a0578063c9cd9760146106b3578063d09ef241146106c6578063d22e9242146106f4578063e30a499314610707578063e5b1be651461071c5761029e565b8063b1af1bda11610113578063b1af1bda14610605578063b32ac93614610625578063ba4d531214610638578063be5813041461064b578063bf6b874e1461066b578063c45a01551461068b5761029e565b80638da5cb5b1461055d57806394531713146105725780639718f627146105855780639d08ebb5146105a5578063a70885c1146105b8578063af482b58146105e55761029e565b80635051349a116101fe578063690910c4116101b7578063690910c4146104cd5780636a42b8f8146104e05780636de3c67c1461050257806377632ec214610517578063793ab297146105375780637f6a1caf1461054a5761029e565b80635051349a14610423578063514fcac71461044357806354df6d7414610463578063576b332b1461049057806357a62a4f146104a35780635e45da23146104b85761029e565b8063390ce0d311610250578063390ce0d3146103545780633bbac579146103815780633ed76f17146103a15780633fc8cef3146103b457806345fa8aae146103d65780634c016016146104035761029e565b806310348665146102a357806313af4035146102b85780631776834a146102cb57806317818a5c146102de57806320a68fab14610314578063342aa8b5146103415761029e565b3661029e57005b600080fd5b6102b66102b13660046153bd565b6107b2565b005b6102b66102c6366004614e25565b610835565b6102b66102d936600461533d565b6108d0565b3480156102ea57600080fd5b506102fe6102f936600461533d565b610967565b60405161030b9190615ca7565b60405180910390f35b34801561032057600080fd5b5061033461032f366004614e25565b610a02565b60405161030b91906157c1565b6102b661034f366004614f5e565b610a0e565b34801561036057600080fd5b5061037461036f36600461533d565b610a9a565b60405161030b91906159fb565b34801561038d57600080fd5b5061033461039c366004614e25565b610b34565b6102b66103af366004614e9d565b610b49565b3480156103c057600080fd5b506103c9610b69565b60405161030b9190615634565b3480156103e257600080fd5b506103f66103f136600461533d565b610b78565b60405161030b9190615822565b34801561040f57600080fd5b5061033461041e366004614e25565b610b84565b6104366104313660046150f5565b610b90565b60405161030b9190615a27565b34801561044f57600080fd5b506102b661045e36600461533d565b610c33565b34801561046f57600080fd5b5061048361047e36600461533d565b610d1c565b60405161030b9190615c76565b61043661049e366004615259565b610db8565b3480156104af57600080fd5b50610436610e1b565b3480156104c457600080fd5b50610436610e21565b6102b66104db366004615259565b610e27565b3480156104ec57600080fd5b506104f5611188565b60405161030b9190615db7565b34801561050e57600080fd5b50610436611194565b34801561052357600080fd5b5061033461053236600461533d565b61119a565b6102b6610545366004614fe3565b6111af565b6102b6610558366004614f96565b611257565b34801561056957600080fd5b506103c96112eb565b6102b661058036600461533d565b6112fa565b34801561059157600080fd5b506104366105a0366004614e25565b61135e565b6104366105b336600461523d565b611379565b3480156105c457600080fd5b506105d86105d3366004614e25565b6113df565b60405161030b9190615d26565b3480156105f157600080fd5b50610334610600366004614e25565b6113f5565b34801561061157600080fd5b5061037461062036600461533d565b611401565b6102b661063336600461533d565b611443565b6104366106463660046150f5565b6114a7565b34801561065757600080fd5b506102b661066636600461533d565b61150d565b34801561067757600080fd5b50610436610686366004614e25565b611556565b34801561069757600080fd5b506103c9611571565b6102b66106ae36600461509b565b611580565b6102b66106c1366004614e5d565b611c66565b3480156106d257600080fd5b506106e66106e136600461533d565b611c95565b60405161030b929190615836565b6102b6610702366004615016565b611cab565b34801561071357600080fd5b50610436611d3d565b6102b661072a366004614f0c565b611d43565b34801561073b57600080fd5b5061033461074a366004614e25565b611f42565b34801561075b57600080fd5b50610436611f4e565b6102b6610772366004615111565b611f54565b6102b661078536600461533d565b6122f5565b6102b661079836600461509b565b61254c565b3480156107a957600080fd5b5061043661279f565b600f546001600160a01b031633146107e55760405162461bcd60e51b81526004016107dc906158ed565b60405180910390fd5b6000805463ffffffff191663ffffffff83161790556040517f63e09f16584208fba1fc7ff64c62b00f07bec177c0d97ca6689891b1e77a35c79061082a908390615db7565b60405180910390a150565b600f546001600160a01b0316331461085f5760405162461bcd60e51b81526004016107dc906158ed565b6001600160a01b0381166108855760405162461bcd60e51b81526004016107dc90615983565b600f80546001600160a01b0319166001600160a01b0383161790556040517f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe29061082a908390615634565b600f546001600160a01b031633146108fa5760405162461bcd60e51b81526004016107dc906158ed565b604051636702eca360e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a90636702eca390610934906000908590600401615c3c565b60006040518083038186803b15801561094c57600080fd5b505af4158015610960573d6000803e3d6000fd5b5050505050565b61096f614b70565b604051634ce4436960e11b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a906399c886d2906109a9906000908690600401615c3c565b6101206040518083038186803b1580156109c257600080fd5b505af41580156109d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109fa9190615275565b90505b919050565b60006109fa81836127a5565b600f546001600160a01b03163314610a385760405162461bcd60e51b81526004016107dc906158ed565b6001600160a01b03821660009081526010602052604090819020805460ff1916831515179055517f70af441dbb427737e6a5ef2cf5b664321011765ce1d19ce4a69cd024e69d4f2f90610a8e9084908490615789565b60405180910390a15050565b610aa2614bd3565b60405163ac1ecdb360e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063ac1ecdb390610adc906000908690600401615c3c565b6101806040518083038186803b158015610af557600080fd5b505af4158015610b09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2d91906150c7565b5092915050565b60106020526000908152604090205460ff1681565b610b5585878684611d43565b610b6183878484611d43565b505050505050565b600e546001600160a01b031690565b60006109fa81836127da565b60006109fa818361287c565b6000601254600014610bb45760405162461bcd60e51b81526004016107dc90615857565b600160125560405162c44ff160e31b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a906306227f8890610bf5906000908690600d90600401615a83565b60006040518083038186803b158015610c0d57600080fd5b505af4158015610c21573d6000803e3d6000fd5b50506001546000601255949350505050565b60125415610c535760405162461bcd60e51b81526004016107dc90615857565b60016012556002610c656000836127da565b6005811115610c7057fe5b14610c8d5760405162461bcd60e51b81526004016107dc90615965565b600080610c9a8184612885565b60005491935063ffffffff90811692504291610cca916201518091610cc49186918116906128ba16565b906128ea565b10610ce75760405162461bcd60e51b81526004016107dc90615875565b6000838152600b60205260409020805460ff19166001908117909155610d129083908390869061292b565b5050600060125550565b610d24614c2f565b60405163117d7ab160e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063117d7ab190610d5e906000908690600401615c3c565b6101e06040518083038186803b158015610d7757600080fd5b505af4158015610d8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610daf919061514c565b50909392505050565b6000601254600014610ddc5760405162461bcd60e51b81526004016107dc90615857565b6001601255604051636587992160e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a90636587992190610bf5906000908690600401615b91565b60085490565b60055490565b333014610e465760405162461bcd60e51b81526004016107dc906158ed565b426202a300610e5d610120840161010085016153bd565b63ffffffff16011015610e825760405162461bcd60e51b81526004016107dc90615947565b60008080610e9e610e9660208601866153bd565b600090612ed7565b925092509250826001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610edf57600080fd5b505af1158015610ef3573d6000803e3d6000fd5b50505050610f0683848660200135612f10565b60008080610f1a60a0880160808901615041565b8015610f4a5750600e546001600160a01b0386811691161480610f4a5750600e546001600160a01b038581169116145b156110b9576000736195015b38773f468dd43620dd5a64e9bb63c2e363cf58beed87878a600d60010160009054906101000a90046001600160a01b03168d60a0016020810190610f9a9190614e25565b60008052600a602052600080516020615e4e833981519152546040516001600160e01b031960e089901b168152610fd996959493929190600401615661565b60806040518083038186803b158015610ff157600080fd5b505af4158015611005573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611029919061505d565b919650945092509050806110b35773412da11751b0a36d03b060890f4e41b7ce32971e63656621e0600d61106360c08c0160a08d01614e25565b876040518463ffffffff1660e01b815260040161108293929190615a64565b60006040518083038186803b15801561109a57600080fd5b505af41580156110ae573d6000803e3d6000fd5b505050505b5061114b565b6001600160a01b0386166389afcb446110d860c08a0160a08b01614e25565b6040518263ffffffff1660e01b81526004016110f49190615634565b6040805180830381600087803b15801561110d57600080fd5b505af1158015611121573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611145919061536d565b90925090505b86604001358210158015611163575086606001358110155b61117f5760405162461bcd60e51b81526004016107dc906158b1565b50505050505050565b60005463ffffffff1690565b60075490565b6000908152600b602052604090205460ff1690565b600f546001600160a01b031633146111d95760405162461bcd60e51b81526004016107dc906158ed565b600a61ffff821611156111fe5760405162461bcd60e51b81526004016107dc90615929565b6001600160a01b03821660009081526011602052604090819020805461ffff191661ffff8416179055517f6b4044e33be5af8fcdb7449c49137010eede3c8c06d5d08067151a7ace17266d90610a8e90849084906157a4565b600f546001600160a01b031633146112815760405162461bcd60e51b81526004016107dc906158ed565b60405163146bce4f60e31b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063a35e7278906112bf90600090879087908790600401615a30565b60006040518083038186803b1580156112d757600080fd5b505af415801561117f573d6000803e3d6000fd5b600f546001600160a01b031681565b600f546001600160a01b031633146113245760405162461bcd60e51b81526004016107dc906158ed565b604051630fd1437d60e11b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a90631fa286fa90610934906000908590600401615c3c565b6001600160a01b03166000908152600a602052604090205490565b600060125460001461139d5760405162461bcd60e51b81526004016107dc90615857565b6001601255604051638f0e6bef60e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a90638f0e6bef90610bf5906000908690600d90600401615aa7565b60116020526000908152604090205461ffff1681565b60006109fa818361305b565b611409614bd3565b6040516311c8197f60e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a906311c8197f90610adc906000908690600401615c3c565b600f546001600160a01b0316331461146d5760405162461bcd60e51b81526004016107dc906158ed565b60405163153cc2fd60e31b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063a9e617e890610934906000908590600401615c3c565b60006012546000146114cb5760405162461bcd60e51b81526004016107dc90615857565b600160125560405163758e99b360e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063758e99b390610bf5906000908690600d90600401615a83565b6012541561152d5760405162461bcd60e51b81526004016107dc90615857565b600160125560008061153f8184613064565b63ffffffff1691509150610d12828285600061292b565b6001600160a01b03166000908152600d602052604090205490565b6004546001600160a01b031690565b33301461159f5760405162461bcd60e51b81526004016107dc906158ed565b426202a3006115b6610120850161010086016153bd565b63ffffffff160110156115db5760405162461bcd60e51b81526004016107dc90615947565b600080806116046115ef60208701876153bd565b6115ff6040880160208901615041565b6130a2565b91945092509050600073412da11751b0a36d03b060890f4e41b7ce32971e63a8d669b4600d8560408a01358961164060c08d0160a08e01614e25565b6040518663ffffffff1660e01b8152600401611660959493929190615c4a565b60206040518083038186803b15801561167857600080fd5b505af415801561168c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b09190615355565b9050836001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156116ed57600080fd5b505af1158015611701573d6000803e3d6000fd5b50505050600061172a858861012001358961014001602081019061172591906153bd565b6130de565b90506000806000806000896001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401604080518083038186803b15801561176c57600080fd5b505afa158015611780573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a4919061530b565b915091506117db60018d60200160208101906117c09190615041565b6117ca57826117cc565b835b6001600160701b0316906128ba565b925050506000886001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561181a57600080fd5b505afa15801561182e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118529190614e41565b90506000896001600160a01b03166354cf2aeb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561188f57600080fd5b505afa1580156118a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c79190615355565b9050816001600160a01b031663daab4b6e8d60200160208101906118eb9190615041565b838f606001358a6040518563ffffffff1660e01b815260040161191194939291906157cc565b604080518083038186803b15801561192857600080fd5b505afa15801561193c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611960919061536d565b9095509350600083851115611a265761198760608e01356119818a876131fc565b90613251565b9050826001600160a01b031663a7d208778e60200160208101906119ab9190615041565b84878b6040518563ffffffff1660e01b81526004016119cd94939291906157cc565b604080518083038186803b1580156119e457600080fd5b505afa1580156119f8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1c919061536d565b9096509450611a30565b5060608c01359350865b85811015611a505760405162461bcd60e51b81526004016107dc906159a1565b85881115611ad557600e546001600160a01b038b81169116148015611a805750611a8060a08e0160808f01615041565b15611aaf57611aaa8d60a0016020810190611a9b9190614e25565b611aa58a896128ba565b613281565b611ad5565b611ad58a8e60a0016020810190611ac69190614e25565b611ad08b8a6128ba565b612f10565b611ae08a8c88612f10565b5050506001600160a01b038816600090815260116020526040902054611b0b90839061ffff166128ba565b9150600080611b2060408d0160208e01615041565b15611b2d57839150611b30565b50825b600e546001600160a01b038981169116148015611b585750611b5860a08d0160808e01615041565b15611be15760405163022c0d9f60e01b81526001600160a01b038b169063022c0d9f90611b8f908590859030908c90600401615d4e565b600060405180830381600087803b158015611ba957600080fd5b505af1158015611bbd573d6000803e3d6000fd5b50611bdc9250611bd691505060c08e0160a08f01614e25565b85613281565b611c58565b896001600160a01b031663022c0d9f83838f60a0016020810190611c059190614e25565b8a6040518563ffffffff1660e01b8152600401611c259493929190615d4e565b600060405180830381600087803b158015611c3f57600080fd5b505af1158015611c53573d6000803e3d6000fd5b505050505b505050505050505050505050565b333014611c855760405162461bcd60e51b81526004016107dc906158ed565b611c90838383612f10565b505050565b600080611ca28184612885565b91509150915091565b600f546001600160a01b03163314611cd55760405162461bcd60e51b81526004016107dc906158ed565b60405163b2456a0760e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063b2456a0790611d119060009086908690600401615a64565b60006040518083038186803b158015611d2957600080fd5b505af4158015610b61573d6000803e3d6000fd5b60015490565b333014611d625760405162461bcd60e51b81526004016107dc906158ed565b600e546001600160a01b038581169116148015611d7c5750805b15611ea357604051632a359a6d60e21b815260009073412da11751b0a36d03b060890f4e41b7ce32971e9063a8d669b490611dc490600d908990889087908b90600401615c4a565b60206040518083038186803b158015611ddc57600080fd5b505af4158015611df0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e149190615355565b600e54604051632e1a7d4d60e01b81529192506001600160a01b031690632e1a7d4d90611e45908490600401615a27565b600060405180830381600087803b158015611e5f57600080fd5b505af1158015611e73573d6000803e3d6000fd5b5050600080525050600a602052600080516020615e4e83398151915254611e9d90859083906133a1565b50611f3c565b604051632a359a6d60e21b8152611f3c908590859073412da11751b0a36d03b060890f4e41b7ce32971e9063a8d669b490611eec90600d9086908a906000908890600401615c4a565b60206040518083038186803b158015611f0457600080fd5b505af4158015611f18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad09190615355565b50505050565b60006109fa8183613433565b60025490565b333014611f735760405162461bcd60e51b81526004016107dc906158ed565b426202a300611f8a610160860161014087016153bd565b63ffffffff16011015611faf5760405162461bcd60e51b81526004016107dc90615947565b600080600080611fc087878761343c565b92965090945092509050611fda60e0880160c08901615041565b8015611fe557508015155b1561220a57835160009061200b906101608a01356117256101a08c016101808d016153bd565b9050831580159061201c5750816001145b1561210d576000730ec2323adafbebc6c80257c7359692bcceb0b3f163d0b0a9bc87600001518860200151888d60600135601160008d600001516001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a900461ffff16886040518763ffffffff1660e01b81526004016120a796959493929190615739565b604080518083038186803b1580156120be57600080fd5b505af41580156120d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120f6919061536d565b909550905061210584826128ea565b935050612208565b821580159061211c5750816002145b15612208576000730ec2323adafbebc6c80257c7359692bcceb0b3f163adf5f8f387600001518860400151878d60800135601160008d600001516001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a900461ffff16886040518763ffffffff1660e01b81526004016121a796959493929190615739565b604080518083038186803b1580156121be57600080fd5b505af41580156121d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f6919061536d565b9450905061220485826128ea565b9450505b505b821580159061221857508115155b156122d0578351730ec2323adafbebc6c80257c7359692bcceb0b3f190637a528bd29061224c6101008b0160e08c01614e25565b8760200151886040015188886040518763ffffffff1660e01b81526004016122799695949392919061569c565b60606040518083038186803b15801561229157600080fd5b505af41580156122a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c99190615390565b5090935091505b61117f6122e4610100890160e08a01614e25565b856020015186604001518686613780565b601254156123155760405162461bcd60e51b81526004016107dc90615857565b60016012556040517f892cd8f5b436bd5fb7dac1f11aafb73345d892ba3e9fe09cd94d95ba84928e739061234c9033908490615648565b60405180910390a160005a3360009081526010602052604081205491925090819060ff16806123a557506000805260106020527f6e0956cda88cad152e89927e53611735b61a5c762d1428573c6931b0a5efcb015460ff165b905060005b848110156124c5576002546001016000908152600b602052604090205460ff16156123de576123d960006137a2565b6124bd565b6000806123eb60006137ae565b909250905060008260048111156123fe57fe5b148061240a5750428110155b156124165750506124c5565b838061242657506104b081014210155b6124425760405162461bcd60e51b81526004016107dc906158ed565b600194508482600481111561245357fe5b1415612466576124616137d2565b6124ba565b600282600481111561247457fe5b141561248257612461613a22565b600382600481111561249057fe5b141561249e57612461613c26565b60048260048111156124ac57fe5b14156124ba576124ba613e84565b50505b6001016123aa565b50811561254157739cb505f2b41aa426257ed2a0bba005fff0af9e9a639db74df160006124f35a87906128ba565b6040518363ffffffff1660e01b8152600401612510929190615c3c565b60006040518083038186803b15801561252857600080fd5b505af415801561253c573d6000803e3d6000fd5b505050505b505060006012555050565b33301461256b5760405162461bcd60e51b81526004016107dc906158ed565b426202a300612582610120850161010086016153bd565b63ffffffff160110156125a75760405162461bcd60e51b81526004016107dc90615947565b600080806125bb6115ef60208701876153bd565b925092509250826001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156125fc57600080fd5b505af1158015612610573d6000803e3d6000fd5b505050506000612634848761012001358861014001602081019061172591906153bd565b905060006126458787878786613f80565b905060008061265a60408a0160208b01615041565b6126665760008361266a565b8260005b600e5491935091506001600160a01b038681169116148015612697575061269760a08a0160808b01615041565b156127205760405163022c0d9f60e01b81526001600160a01b0388169063022c0d9f906126ce908590859030908a90600401615d4e565b600060405180830381600087803b1580156126e857600080fd5b505af11580156126fc573d6000803e3d6000fd5b5061271b925061271591505060c08b0160a08c01614e25565b84613281565b612794565b6001600160a01b03871663022c0d9f838361274160c08e0160a08f01614e25565b886040518563ffffffff1660e01b81526004016127619493929190615d4e565b600060405180830381600087803b15801561277b57600080fd5b505af115801561278f573d6000803e3d6000fd5b505050505b505050505050505050565b60065490565b600060025b6001600160a01b0383166000908152600c85016020526040902054600160ff9283161b1616151590505b92915050565b600082600101548211156127f0575060006127d4565b6000828152600b8401602052604090205460ff1615612811575060056127d4565b61281b8383614467565b15612828575060046127d4565b6000806128358585612885565b9092509050600082600481111561284857fe5b1415612859576003925050506127d4565b428163ffffffff1610612871576001925050506127d4565b506002949350505050565b600060036127aa565b60008181526003830160205260408120805463ffffffff61010082041691906128b09060ff1661449e565b9250509250929050565b60006128e383836040518060400160405280600481526020016329a6989960e11b81525061450e565b9392505050565b808201828110156127d4576040805162461bcd60e51b81526020600480830191909152602482015263534d344560e01b604482015290519081900360640190fd5b600084600481111561293957fe5b14156129575760405162461bcd60e51b81526004016107dc906159bf565b600042612968856301e133806128ea565b109050600185600481111561297957fe5b1415612ad75760405163117d7ab160e01b8152600090739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063117d7ab1906129bb9084908890600401615c3c565b6101e06040518083038186803b1580156129d457600080fd5b505af41580156129e8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a0c919061514c565b50509050600080612a2b83600001516000612ed790919063ffffffff16565b9250925050600084612a41578360e00151612a4e565b600f546001600160a01b03165b9050612a6a818486602001518588604001518960a001516145a6565b612a865760405162461bcd60e51b81526004016107dc90615893565b8515612ace57612ab281612aad8661012001518761010001516131fc90919063ffffffff16565b614730565b612ace5760405162461bcd60e51b81526004016107dc9061590b565b50505050612ecc565b6002856004811115612ae557fe5b1415612c2b57604051634ce4436960e11b8152600090739cb505f2b41aa426257ed2a0bba005fff0af9e9a906399c886d290612b279084908890600401615c3c565b6101206040518083038186803b158015612b4057600080fd5b505af4158015612b54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b789190615275565b8051909150600090612b8b908290612ed7565b50509050600083612ba0578260a00151612bad565b600f546001600160a01b03165b9050612bc68282856020015163c9cd976060e01b6147b1565b612be25760405162461bcd60e51b81526004016107dc90615893565b8415612c2357612c0781612aad8560e001518660c001516131fc90919063ffffffff16565b612c235760405162461bcd60e51b81526004016107dc9061590b565b505050612ecc565b6003856004811115612c3957fe5b1415612d745760405163ac1ecdb360e01b8152600090739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063ac1ecdb390612c7b9084908890600401615c3c565b6101806040518083038186803b158015612c9457600080fd5b505af4158015612ca8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ccc91906150c7565b509050600080612cea83600001516000612ed790919063ffffffff16565b9250925050600084612d00578360a00151612d0d565b600f546001600160a01b03165b9050612d338460200151612d215783612d23565b825b82866040015187608001516148cc565b612d4f5760405162461bcd60e51b81526004016107dc90615893565b8515612ace57612ab281612aad8660e001518760c001516131fc90919063ffffffff16565b6004856004811115612d8257fe5b1415612ecc576040516311c8197f60e01b8152600090739cb505f2b41aa426257ed2a0bba005fff0af9e9a906311c8197f90612dc49084908890600401615c3c565b6101806040518083038186803b158015612ddd57600080fd5b505af4158015612df1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e1591906150c7565b509050600080612e3383600001516000612ed790919063ffffffff16565b9250925050600084612e49578360a00151612e56565b600f546001600160a01b03165b9050612e6a8460200151612d215783612d23565b612e865760405162461bcd60e51b81526004016107dc90615893565b8515612ec757612eab81612aad8660e001518760c001516131fc90919063ffffffff16565b612ec75760405162461bcd60e51b81526004016107dc9061590b565b505050505b610960600084614918565b63ffffffff166000908152600990910160205260409020805460018201546002909201546001600160a01b039182169392821692911690565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b60208310612f8c5780518252601f199092019160209182019101612f6d565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612fee576040519150601f19603f3d011682016040523d82523d6000602084013e612ff3565b606091505b5091509150818015613021575080511580613021575080806020019051602081101561301e57600080fd5b50515b610960576040805162461bcd60e51b815260206004808301919091526024820152635448303560e01b604482015290519081900360640190fd5b600060016127aa565b6000806130718484614467565b61308d5760405162461bcd60e51b81526004016107dc906159dd565b6130978484612885565b909590945092505050565b600080808080806130b38189612ed7565b925092509250600080886130c85783836130cb565b82845b9598509650939450505050509250925092565b60606000846001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561311b57600080fd5b505afa15801561312f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131539190614e41565b6001600160a01b0316638c09166e85856040518363ffffffff1660e01b8152600401613180929190615da3565b60206040518083038186803b15801561319857600080fd5b505afa1580156131ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131d09190615355565b9050806040516020016131e39190615a27565b6040516020818303038152906040529150509392505050565b60008115806132175750508082028282828161321457fe5b04145b6127d4576040805162461bcd60e51b81526020600480830191909152602482015263534d324160e01b604482015290519081900360640190fd5b600061325d838361495c565b905061326982826131fc565b83146127d45761327a8160016128ea565b90506127d4565b600e54604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906132b1908490600401615a27565b600060405180830381600087803b1580156132cb57600080fd5b505af11580156132df573d6000803e3d6000fd5b50506000808052600a602052600080516020615e4e833981519152546040519193506001600160a01b038616925090849061331990615631565b600060405180830381858888f193505050503d8060008114613357576040519150601f19603f3d011682016040523d82523d6000602084013e61335c565b606091505b5050905080611c905760405163032b310f60e51b815273412da11751b0a36d03b060890f4e41b7ce32971e9063656621e0906112bf90600d9087908790600401615a64565b6040516000906001600160a01b038516908390859084818181858888f193505050503d80600081146133ef576040519150601f19603f3d011682016040523d82523d6000602084013e6133f4565b606091505b5050905080611f3c576040805162461bcd60e51b815260206004808301919091526024820152632a2419a360e11b604482015290519081900360640190fd5b600060046127aa565b613444614cb6565b6000808060098161345860208a018a6153bd565b63ffffffff1663ffffffff1681526020019081526020016000206040518060600160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016002820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152505093506000600d73412da11751b0a36d03b060890f4e41b7ce32971e63a8d669b4909187602001518b602001358b8d60e001602081019061354a9190614e25565b6040518663ffffffff1660e01b815260040161356a959493929190615c4a565b60206040518083038186803b15801561358257600080fd5b505af4158015613596573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ba9190615355565b90506000600d73412da11751b0a36d03b060890f4e41b7ce32971e63a8d669b4909188604001518c604001358b8e60e00160208101906135fa9190614e25565b6040518663ffffffff1660e01b815260040161361a959493929190615c4a565b60206040518083038186803b15801561363257600080fd5b505af4158015613646573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061366a9190615355565b905085600001516001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156136ab57600080fd5b505af11580156136bf573d6000803e3d6000fd5b50508751730ec2323adafbebc6c80257c7359692bcceb0b3f19250637a528bd291506136f26101008d0160e08e01614e25565b89602001518a6040015187876040518763ffffffff1660e01b815260040161371f9695949392919061569c565b60606040518083038186803b15801561373757600080fd5b505af415801561374b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061376f9190615390565b979b919a5098509596505050505050565b811561379157613791848684612f10565b801561096057610960838683612f10565b60020180546001019055565b6000806137c2838460020154600101612885565b90925063ffffffff169050915091565b60005a9050600080600080739cb505f2b41aa426257ed2a0bba005fff0af9e9a63a81df10f90916040518263ffffffff1660e01b81526004016138159190615a27565b6101e06040518083038186803b15801561382e57600080fd5b505af4158015613842573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613866919061514c565b92509250925060008061388785600001516000612ed790919063ffffffff16565b6001600160a01b038082166000908152600a6020526040808220549285168252812054939650919450909250829130916138da916138ce9190610cc49062012c6c906128ea565b6101208a0151906128ba565b6040516378b2847b60e11b906138f8908b908b908b90602401615c85565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516139369190615615565b60006040518083038160008787f1925050503d8060008114613974576040519150601f19603f3d011682016040523d82523d6000602084013e613979565b606091505b5090925090506001826139a7576139a48860e00151868a60200151878c604001518d60a001516145a6565b90505b6139b0816149ac565b6000806139cd8a61012001518b61010001518d8d60e001516149cd565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613a0d939291906157fd565b60405180910390a35050505050505050505050565b60005a6040516313ed2f6160e01b8152909150600090739cb505f2b41aa426257ed2a0bba005fff0af9e9a906313ed2f6190613a62908490600401615a27565b6101206040518083038186803b158015613a7b57600080fd5b505af4158015613a8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ab39190615275565b905060008030613ad6613acb62012c6c61d6d86128ea565b60e0860151906128ba565b604051631a42443160e21b90613af0908790602401615ca7565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613b2e9190615615565b60006040518083038160008787f1925050503d8060008114613b6c576040519150601f19603f3d011682016040523d82523d6000602084013e613b71565b606091505b509092509050600182613bb1578351600090613b8e908290612ed7565b50509050613bad818660a00151876020015163c9cd976060e01b6147b1565b9150505b613bba816149ac565b600080613bd58660e001518760c00151898960a001516149cd565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613c15939291906157fd565b60405180910390a350505050505050565b60005a604051632e9d30e160e01b81529091506000908190739cb505f2b41aa426257ed2a0bba005fff0af9e9a90632e9d30e190613c68908490600401615a27565b6101806040518083038186803b158015613c8157600080fd5b505af4158015613c95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cb991906150c7565b91509150600080613cd884600001516000612ed790919063ffffffff16565b9250925050600080306001600160a01b0316613d37613d2c6000600a0160008a60200151613d065788613d08565b875b6001600160a01b0316815260208101919091526040016000205462012c6c906128ea565b60e0890151906128ba565b604051637f09b54760e11b90613d53908a908a90602401615a0a565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613d919190615615565b60006040518083038160008787f1925050503d8060008114613dcf576040519150601f19603f3d011682016040523d82523d6000602084013e613dd4565b606091505b509092509050600182613e0c57613e098760200151613df35785613df5565b845b8860a0015189604001518a608001516148cc565b90505b613e15816149ac565b600080613e308960e001518a60c001518c8c60a001516149cd565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613e70939291906157fd565b60405180910390a350505050505050505050565b60005a60405163a1ba139560e01b81529091506000908190739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063a1ba139590613ec6908490600401615a27565b6101806040518083038186803b158015613edf57600080fd5b505af4158015613ef3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f1791906150c7565b91509150600080613f3684600001516000612ed790919063ffffffff16565b9250925050600080306001600160a01b0316613f64613d2c6000600a0160008a60200151613d065788613d08565b60405163634e773960e11b90613d53908a908a90602401615a0a565b600080600080866001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401604080518083038186803b158015613fbe57600080fd5b505afa158015613fd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ff6919061530b565b909250905061401060016117c060408c0160208d01615041565b925050506000856001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561404f57600080fd5b505afa158015614063573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140879190614e41565b90506000866001600160a01b03166354cf2aeb6040518163ffffffff1660e01b815260040160206040518083038186803b1580156140c457600080fd5b505afa1580156140d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140fc9190615355565b90506000600d73412da11751b0a36d03b060890f4e41b7ce32971e63a8d669b49091898d604001358d8f60a00160208101906141389190614e25565b6040518663ffffffff1660e01b8152600401614158959493929190615c4a565b60206040518083038186803b15801561417057600080fd5b505af4158015614184573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141a89190615355565b90506141ba60408b0160208c01615041565b614243576040516304a8fad760e31b81526001600160a01b03841690632547d6b8906141ee90859085908b90600401615d7b565b60206040518083038186803b15801561420657600080fd5b505afa15801561421a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061423e9190615355565b6142c3565b60405163c4109d2560e01b81526001600160a01b0384169063c4109d259061427390859085908b90600401615d7b565b60206040518083038186803b15801561428b57600080fd5b505afa15801561429f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142c39190615355565b94506000848611156143fd576142e7866142e160608e0135886131fc565b9061495c565b90506000829050846001600160a01b031663a7d208778d60200160208101906143109190615041565b86898c6040518563ffffffff1660e01b815260040161433294939291906157cc565b604080518083038186803b15801561434957600080fd5b505afa15801561435d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614381919061536d565b600e549098509093506001600160a01b038a811691161480156143af57506143af60a08d0160808e01615041565b156143d6576143d16143c760c08e0160a08f01614e25565b611aa583866128ba565b6143f7565b6143f7898d60a00160208101906143ed9190614e25565b611ad084876128ba565b50614404565b5060608a01355b6001600160a01b03891660009081526011602052604090205461442c90879061ffff166128ba565b95508086101561444e5760405162461bcd60e51b81526004016107dc906158cf565b614459888a84612f10565b505050505095945050505050565b600081815260038301602052604081205465010000000000900460ff166002811480614496575060ff81166003145b949350505050565b600060018214156144b1575060016109fd565b60028214156144c2575060026109fd565b60038214156144d3575060046109fd565b60048214156144e4575060046109fd565b60058214156144f5575060036109fd565b6006821415614506575060036109fd565b506000919050565b818303818482111561459e5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561456357818101518382015260200161454b565b50505050905090810190601f1680156145905780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509392505050565b6001600160a01b038381166000908152600a602052604080822054928816825281205490918291829130916145da916128ea565b604051633ed76f1760e01b906145fe908d908d908d908d908d908d906024016156d6565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161463c9190615615565b60006040518083038160008787f1925050503d806000811461467a576040519150601f19603f3d011682016040523d82523d6000602084013e61467f565b606091505b50915091508161472457876001600160a01b0316896001600160a01b03167f786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b21159289846040516146ce929190615d35565b60405180910390a3856001600160a01b0316896001600160a01b03167f786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b211592878460405161471b929190615d35565b60405180910390a35b50979650505050505050565b60008161473f575060016127d4565b60008052600a602052600080516020615e4e833981519152546147659084908490614a5d565b9050801515836001600160a01b03167fdbef2fc26e7694e7a1c5a4801b1ad144136d149cf76f310a780689b4087f0ffe846040516147a39190615a27565b60405180910390a392915050565b6000826147c057506001614496565b600080306001600160a01b031661d6d88589898960006040516024016147e99493929190615710565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516148279190615615565b60006040518083038160008787f1925050503d8060008114614865576040519150601f19603f3d011682016040523d82523d6000602084013e61486a565b606091505b5091509150816148c257866001600160a01b0316866001600160a01b03167f786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b21159287846040516148b9929190615d35565b60405180910390a35b5095945050505050565b6000826148db57506001614496565b6001600160a01b0385166000908152600a60205260408082205490518291309163e5b1be6560e01b906147e9908b908b908b908b90602401615710565b6000908152600391820160205260408120818155600181018290556002810180546001600160e81b03191690559182015560040180546001600160e01b0319169055565b600080821161499b576040805162461bcd60e51b81526020600480830191909152602482015263534d343360e01b604482015290519081900360640190fd5b8183816149a457fe5b049392505050565b806149c0576149bb6000614abb565b6149ca565b6149ca6000614b0e565b50565b600080806149db87876131fc565b90506149ee615594610cc45a88906128ba565b92506000614a1382614a0e600060060154876131fc90919063ffffffff16565b614b5a565b9050614a1f82826128ba565b9250614a2b3382614730565b614a475760405162461bcd60e51b81526004016107dc9061590b565b614a518584614730565b50505094509492505050565b6040516000906001600160a01b038516908390859084818181858888f193505050503d8060008114614aab576040519150601f19603f3d011682016040523d82523d6000602084013e614ab0565b606091505b509095945050505050565b600281015460009081526003820160205260409020805465010000000000900460ff1615614aea576003614aed565b60025b815460ff91909116650100000000000265ff00000000001990911617905550565b60028082015460009081526003928301602052604081208181556001810182905591820180546001600160e81b03191690559181019190915560040180546001600160e01b0319169055565b6000818310614b6957816128e3565b5090919050565b604051806101200160405280600063ffffffff16815260200160008152602001600081526020016000815260200160001515815260200160006001600160a01b031681526020016000815260200160008152602001600063ffffffff1681525090565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b604051806101a00160405280600063ffffffff1681526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160006001600160a01b031681526020016000815260200160008152602001600063ffffffff16815260200160008152602001600063ffffffff1681525090565b604080516060810182526000808252602082018190529181019190915290565b80356109fd81615e18565b80516109fd81615e18565b80356109fd81615e2d565b80516109fd81615e2d565b60006101608284031215614d14578081fd5b50919050565b6000610160808385031215614d2d578182fd5b614d3681615dc8565b915050614d4282614e1a565b8152614d5060208301614cf7565b60208201526040820151604082015260608201516060820152614d7560808301614cf7565b6080820152614d8660a08301614ce1565b60a082015260c082015160c082015260e082015160e0820152610100614dad818401614e1a565b908201526101208281015190820152610140614dca818401614e1a565b9082015292915050565b60006101008284031215614d14578081fd5b60006101208284031215614d14578081fd5b80516001600160701b03811681146109fd57600080fd5b80356109fd81615e3b565b80516109fd81615e3b565b600060208284031215614e36578081fd5b81356128e381615e18565b600060208284031215614e52578081fd5b81516128e381615e18565b600080600060608486031215614e71578182fd5b8335614e7c81615e18565b92506020840135614e8c81615e18565b929592945050506040919091013590565b60008060008060008060c08789031215614eb5578384fd5b8635614ec081615e18565b95506020870135614ed081615e18565b9450604087013593506060870135614ee781615e18565b92506080870135915060a0870135614efe81615e2d565b809150509295509295509295565b60008060008060808587031215614f21578182fd5b8435614f2c81615e18565b93506020850135614f3c81615e18565b9250604085013591506060850135614f5381615e2d565b939692955090935050565b60008060408385031215614f70578182fd5b8235614f7b81615e18565b91506020830135614f8b81615e2d565b809150509250929050565b600080600060608486031215614faa578081fd5b8335614fb581615e18565b9250602084013560058110614fc8578182fd5b91506040840135614fd881615e2d565b809150509250925092565b60008060408385031215614ff5578182fd5b823561500081615e18565b9150602083013561ffff81168114614f8b578182fd5b60008060408385031215615028578182fd5b823561503381615e18565b946020939093013593505050565b600060208284031215615052578081fd5b81356128e381615e2d565b60008060008060808587031215615072578182fd5b845161507d81615e2d565b60208601516040870151606090970151919890975090945092505050565b60008061018083850312156150ae578182fd5b6150b88484614d02565b94610160939093013593505050565b60008061018083850312156150da578182fd5b6150e48484614d1a565b915061016083015190509250929050565b60006101008284031215615107578081fd5b6128e38383614dd4565b60008060008385036101e0811215615127578182fd5b6101a080821215615136578283fd5b949694870135955050506101c085013592915050565b60008060008385036101e0811215615162578182fd5b6101a080821215615171578283fd5b61517a81615dc8565b915061518586614e1a565b8252602086015160208301526040860151604083015260608601516060830152608086015160808301526151bb60a08701614cf7565b60a08301526151cc60c08701614cf7565b60c08301526151dd60e08701614ce1565b60e083015261010086810151908301526101208087015190830152610140615206818801614e1a565b908301526101608681015190830152610180615223818801614e1a565b908301528501516101c09095015190969495509392505050565b6000610160828403121561524f578081fd5b6128e38383614d02565b6000610120828403121561526b578081fd5b6128e38383614de6565b6000610120808385031215615288578182fd5b61529181615dc8565b905061529c83614e1a565b81526020830151602082015260408301516040820152606083015160608201526152c860808401614cf7565b60808201526152d960a08401614ce1565b60a082015260c083015160c082015260e083015160e0820152610100615300818501614e1a565b908201529392505050565b6000806040838503121561531d578182fd5b61532683614df8565b915061533460208401614df8565b90509250929050565b60006020828403121561534e578081fd5b5035919050565b600060208284031215615366578081fd5b5051919050565b6000806040838503121561537f578182fd5b505080516020909101519092909150565b6000806000606084860312156153a4578081fd5b8351925060208401519150604084015190509250925092565b6000602082840312156153ce578081fd5b81356128e381615e3b565b6001600160a01b03169052565b15159052565b60008151808452615404816020860160208601615dec565b601f01601f19169290920160200192915050565b6005811061542257fe5b9052565b61543182825161560b565b602081015161544360208401826153e6565b506040810151604083015260608101516060830152608081015161546a60808401826153e6565b5060a081015161547d60a08401826153d9565b5060c081015160c083015260e081015160e0830152610100808201516154a58285018261560b565b5050610120818101519083015261014080820151611f3c8285018261560b565b80356154d081615e18565b6001600160a01b0390811683526020820135906154ec82615e18565b1660208301526040818101359083015260608082013590830152608081013561551481615e2d565b1515608083015260a081013561552981615e18565b61553660a08401826153d9565b5060c081013560c083015261554d60e08201614e0f565b611c9060e084018261560b565b61556582825161560b565b6020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015161559f60a08401826153e6565b5060c08101516155b260c08401826153e6565b5060e08101516155c560e08401826153d9565b5061010081810151908301526101208082015190830152610140808201516155ef8285018261560b565b5050610160818101519083015261018080820151611f3c828501825b63ffffffff169052565b60008251615627818460208701615dec565b9190910192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039687168152948616602086015292851660408501529084166060840152909216608082015260a081019190915260c00190565b6001600160a01b0396871681529486166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b6001600160a01b0396871681529486166020860152604085019390935293166060830152608082019290925290151560a082015260c00190565b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b6001600160a01b03878116825286166020820152604081018590526060810184905261ffff8316608082015260c060a0820181905260009061577d908301846153ec565b98975050505050505050565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b0392909216825261ffff16602082015260400190565b901515815260200190565b60008515158252846020830152836040830152608060608301526157f360808301846153ec565b9695505050505050565b60006060825261581060608301866153ec565b60208301949094525060400152919050565b602081016006831061583057fe5b91905290565b604081016158448285615418565b63ffffffff831660208301529392505050565b6020808252600490820152632a22181b60e11b604082015260600190565b6020808252600490820152635444314360e01b604082015260600190565b60208082526004908201526315110c4d60e21b604082015260600190565b6020808252600490820152635444303360e01b604082015260600190565b6020808252600490820152635444333760e01b604082015260600190565b6020808252600490820152630544430360e41b604082015260600190565b6020808252600490820152630544434360e41b604082015260600190565b60208082526004908201526315110d4d60e21b604082015260600190565b60208082526004908201526315110c0d60e21b604082015260600190565b6020808252600490820152632a221a9960e11b604082015260600190565b6020808252600490820152632a22181960e11b604082015260600190565b6020808252600490820152630a88860760e31b604082015260600190565b6020808252600490820152635444343160e01b604082015260600190565b6020808252600490820152634f53323160e01b604082015260600190565b61016081016127d48284615426565b6101808101615a198285615426565b826101608301529392505050565b90815260200190565b8481526001600160a01b038416602082015260808101615a536040830185615418565b821515606083015295945050505050565b9283526001600160a01b03919091166020830152604082015260600190565b8381526101408101615a9860208301856154c5565b82610120830152949350505050565b8381526101a08101615ac460208301615abf86614cd6565b6153d9565b615ad060208501614cd6565b615add60408401826153d9565b506040840135606083015260608401356080830152608084013560a083015260a084013560c0830152615b1260c08501614cec565b615b1f60e08401826153e6565b50615b2c60e08501614cec565b610100615b3b818501836153e6565b615b46818701614cd6565b915050610120615b58818501836153d9565b6101409150808601358285015250615b71818601614e0f565b9050615b8161016084018261560b565b5082610180830152949350505050565b8281526101408101615ba960208301615abf85614cd6565b615bb560208401614cd6565b615bc260408401826153d9565b506040830135606083015260608301356080830152608083013560a0830152615bed60a08401614cec565b615bfa60c08401826153e6565b50615c0760c08401614cd6565b615c1460e08401826153d9565b5061010060e084013581840152615c2c818501614e0f565b905061459e61012084018261560b565b918252602082015260400190565b9485526001600160a01b0393841660208601526040850192909252606084015216608082015260a00190565b6101a081016127d4828461555a565b6101e08101615c94828661555a565b6101a08201939093526101c00152919050565b60006101208201905063ffffffff835116825260208301516020830152604083015160408301526060830151606083015260808301511515608083015260a0830151615cf660a08401826153d9565b5060c083015160c083015260e083015160e083015261010080840151615d1e8285018261560b565b505092915050565b61ffff91909116815260200190565b60008382526040602083015261449660408301846153ec565b600085825284602083015260018060a01b0384166040830152608060608301526157f360808301846153ec565b600084825283602083015260606040830152615d9a60608301846153ec565b95945050505050565b91825263ffffffff16602082015260400190565b63ffffffff91909116815260200190565b60405181810167ffffffffffffffff81118282101715615de457fe5b604052919050565b60005b83811015615e07578181015183820152602001615def565b83811115611f3c5750506000910152565b6001600160a01b03811681146149ca57600080fd5b80151581146149ca57600080fd5b63ffffffff811681146149ca57600080fdfe13da86008ba1c6922daee3e07db95305ef49ebced9f5467a0b8613fcc6b343e3a26469706673582212209aca9082c087ade6eb58f802c44cd779e0548502d9867d5aa9a7369a3e2d997564736f6c63430007060033000000000000000000000000c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c6000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000003a1d749fa4a9e650fce844ff1c58c5faf7e2a9d1
Deployed Bytecode
0x6080604052600436106102975760003560e01c80638da5cb5b1161015a578063c69cee72116100c1578063e5e7988e1161007a578063e5e7988e1461072f578063e6a0cc941461074f578063f16508f614610764578063fe0d94c114610777578063fe136a8e1461078a578063fe173b971461079d5761029e565b8063c69cee72146106a0578063c9cd9760146106b3578063d09ef241146106c6578063d22e9242146106f4578063e30a499314610707578063e5b1be651461071c5761029e565b8063b1af1bda11610113578063b1af1bda14610605578063b32ac93614610625578063ba4d531214610638578063be5813041461064b578063bf6b874e1461066b578063c45a01551461068b5761029e565b80638da5cb5b1461055d57806394531713146105725780639718f627146105855780639d08ebb5146105a5578063a70885c1146105b8578063af482b58146105e55761029e565b80635051349a116101fe578063690910c4116101b7578063690910c4146104cd5780636a42b8f8146104e05780636de3c67c1461050257806377632ec214610517578063793ab297146105375780637f6a1caf1461054a5761029e565b80635051349a14610423578063514fcac71461044357806354df6d7414610463578063576b332b1461049057806357a62a4f146104a35780635e45da23146104b85761029e565b8063390ce0d311610250578063390ce0d3146103545780633bbac579146103815780633ed76f17146103a15780633fc8cef3146103b457806345fa8aae146103d65780634c016016146104035761029e565b806310348665146102a357806313af4035146102b85780631776834a146102cb57806317818a5c146102de57806320a68fab14610314578063342aa8b5146103415761029e565b3661029e57005b600080fd5b6102b66102b13660046153bd565b6107b2565b005b6102b66102c6366004614e25565b610835565b6102b66102d936600461533d565b6108d0565b3480156102ea57600080fd5b506102fe6102f936600461533d565b610967565b60405161030b9190615ca7565b60405180910390f35b34801561032057600080fd5b5061033461032f366004614e25565b610a02565b60405161030b91906157c1565b6102b661034f366004614f5e565b610a0e565b34801561036057600080fd5b5061037461036f36600461533d565b610a9a565b60405161030b91906159fb565b34801561038d57600080fd5b5061033461039c366004614e25565b610b34565b6102b66103af366004614e9d565b610b49565b3480156103c057600080fd5b506103c9610b69565b60405161030b9190615634565b3480156103e257600080fd5b506103f66103f136600461533d565b610b78565b60405161030b9190615822565b34801561040f57600080fd5b5061033461041e366004614e25565b610b84565b6104366104313660046150f5565b610b90565b60405161030b9190615a27565b34801561044f57600080fd5b506102b661045e36600461533d565b610c33565b34801561046f57600080fd5b5061048361047e36600461533d565b610d1c565b60405161030b9190615c76565b61043661049e366004615259565b610db8565b3480156104af57600080fd5b50610436610e1b565b3480156104c457600080fd5b50610436610e21565b6102b66104db366004615259565b610e27565b3480156104ec57600080fd5b506104f5611188565b60405161030b9190615db7565b34801561050e57600080fd5b50610436611194565b34801561052357600080fd5b5061033461053236600461533d565b61119a565b6102b6610545366004614fe3565b6111af565b6102b6610558366004614f96565b611257565b34801561056957600080fd5b506103c96112eb565b6102b661058036600461533d565b6112fa565b34801561059157600080fd5b506104366105a0366004614e25565b61135e565b6104366105b336600461523d565b611379565b3480156105c457600080fd5b506105d86105d3366004614e25565b6113df565b60405161030b9190615d26565b3480156105f157600080fd5b50610334610600366004614e25565b6113f5565b34801561061157600080fd5b5061037461062036600461533d565b611401565b6102b661063336600461533d565b611443565b6104366106463660046150f5565b6114a7565b34801561065757600080fd5b506102b661066636600461533d565b61150d565b34801561067757600080fd5b50610436610686366004614e25565b611556565b34801561069757600080fd5b506103c9611571565b6102b66106ae36600461509b565b611580565b6102b66106c1366004614e5d565b611c66565b3480156106d257600080fd5b506106e66106e136600461533d565b611c95565b60405161030b929190615836565b6102b6610702366004615016565b611cab565b34801561071357600080fd5b50610436611d3d565b6102b661072a366004614f0c565b611d43565b34801561073b57600080fd5b5061033461074a366004614e25565b611f42565b34801561075b57600080fd5b50610436611f4e565b6102b6610772366004615111565b611f54565b6102b661078536600461533d565b6122f5565b6102b661079836600461509b565b61254c565b3480156107a957600080fd5b5061043661279f565b600f546001600160a01b031633146107e55760405162461bcd60e51b81526004016107dc906158ed565b60405180910390fd5b6000805463ffffffff191663ffffffff83161790556040517f63e09f16584208fba1fc7ff64c62b00f07bec177c0d97ca6689891b1e77a35c79061082a908390615db7565b60405180910390a150565b600f546001600160a01b0316331461085f5760405162461bcd60e51b81526004016107dc906158ed565b6001600160a01b0381166108855760405162461bcd60e51b81526004016107dc90615983565b600f80546001600160a01b0319166001600160a01b0383161790556040517f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe29061082a908390615634565b600f546001600160a01b031633146108fa5760405162461bcd60e51b81526004016107dc906158ed565b604051636702eca360e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a90636702eca390610934906000908590600401615c3c565b60006040518083038186803b15801561094c57600080fd5b505af4158015610960573d6000803e3d6000fd5b5050505050565b61096f614b70565b604051634ce4436960e11b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a906399c886d2906109a9906000908690600401615c3c565b6101206040518083038186803b1580156109c257600080fd5b505af41580156109d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109fa9190615275565b90505b919050565b60006109fa81836127a5565b600f546001600160a01b03163314610a385760405162461bcd60e51b81526004016107dc906158ed565b6001600160a01b03821660009081526010602052604090819020805460ff1916831515179055517f70af441dbb427737e6a5ef2cf5b664321011765ce1d19ce4a69cd024e69d4f2f90610a8e9084908490615789565b60405180910390a15050565b610aa2614bd3565b60405163ac1ecdb360e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063ac1ecdb390610adc906000908690600401615c3c565b6101806040518083038186803b158015610af557600080fd5b505af4158015610b09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2d91906150c7565b5092915050565b60106020526000908152604090205460ff1681565b610b5585878684611d43565b610b6183878484611d43565b505050505050565b600e546001600160a01b031690565b60006109fa81836127da565b60006109fa818361287c565b6000601254600014610bb45760405162461bcd60e51b81526004016107dc90615857565b600160125560405162c44ff160e31b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a906306227f8890610bf5906000908690600d90600401615a83565b60006040518083038186803b158015610c0d57600080fd5b505af4158015610c21573d6000803e3d6000fd5b50506001546000601255949350505050565b60125415610c535760405162461bcd60e51b81526004016107dc90615857565b60016012556002610c656000836127da565b6005811115610c7057fe5b14610c8d5760405162461bcd60e51b81526004016107dc90615965565b600080610c9a8184612885565b60005491935063ffffffff90811692504291610cca916201518091610cc49186918116906128ba16565b906128ea565b10610ce75760405162461bcd60e51b81526004016107dc90615875565b6000838152600b60205260409020805460ff19166001908117909155610d129083908390869061292b565b5050600060125550565b610d24614c2f565b60405163117d7ab160e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063117d7ab190610d5e906000908690600401615c3c565b6101e06040518083038186803b158015610d7757600080fd5b505af4158015610d8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610daf919061514c565b50909392505050565b6000601254600014610ddc5760405162461bcd60e51b81526004016107dc90615857565b6001601255604051636587992160e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a90636587992190610bf5906000908690600401615b91565b60085490565b60055490565b333014610e465760405162461bcd60e51b81526004016107dc906158ed565b426202a300610e5d610120840161010085016153bd565b63ffffffff16011015610e825760405162461bcd60e51b81526004016107dc90615947565b60008080610e9e610e9660208601866153bd565b600090612ed7565b925092509250826001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610edf57600080fd5b505af1158015610ef3573d6000803e3d6000fd5b50505050610f0683848660200135612f10565b60008080610f1a60a0880160808901615041565b8015610f4a5750600e546001600160a01b0386811691161480610f4a5750600e546001600160a01b038581169116145b156110b9576000736195015b38773f468dd43620dd5a64e9bb63c2e363cf58beed87878a600d60010160009054906101000a90046001600160a01b03168d60a0016020810190610f9a9190614e25565b60008052600a602052600080516020615e4e833981519152546040516001600160e01b031960e089901b168152610fd996959493929190600401615661565b60806040518083038186803b158015610ff157600080fd5b505af4158015611005573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611029919061505d565b919650945092509050806110b35773412da11751b0a36d03b060890f4e41b7ce32971e63656621e0600d61106360c08c0160a08d01614e25565b876040518463ffffffff1660e01b815260040161108293929190615a64565b60006040518083038186803b15801561109a57600080fd5b505af41580156110ae573d6000803e3d6000fd5b505050505b5061114b565b6001600160a01b0386166389afcb446110d860c08a0160a08b01614e25565b6040518263ffffffff1660e01b81526004016110f49190615634565b6040805180830381600087803b15801561110d57600080fd5b505af1158015611121573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611145919061536d565b90925090505b86604001358210158015611163575086606001358110155b61117f5760405162461bcd60e51b81526004016107dc906158b1565b50505050505050565b60005463ffffffff1690565b60075490565b6000908152600b602052604090205460ff1690565b600f546001600160a01b031633146111d95760405162461bcd60e51b81526004016107dc906158ed565b600a61ffff821611156111fe5760405162461bcd60e51b81526004016107dc90615929565b6001600160a01b03821660009081526011602052604090819020805461ffff191661ffff8416179055517f6b4044e33be5af8fcdb7449c49137010eede3c8c06d5d08067151a7ace17266d90610a8e90849084906157a4565b600f546001600160a01b031633146112815760405162461bcd60e51b81526004016107dc906158ed565b60405163146bce4f60e31b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063a35e7278906112bf90600090879087908790600401615a30565b60006040518083038186803b1580156112d757600080fd5b505af415801561117f573d6000803e3d6000fd5b600f546001600160a01b031681565b600f546001600160a01b031633146113245760405162461bcd60e51b81526004016107dc906158ed565b604051630fd1437d60e11b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a90631fa286fa90610934906000908590600401615c3c565b6001600160a01b03166000908152600a602052604090205490565b600060125460001461139d5760405162461bcd60e51b81526004016107dc90615857565b6001601255604051638f0e6bef60e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a90638f0e6bef90610bf5906000908690600d90600401615aa7565b60116020526000908152604090205461ffff1681565b60006109fa818361305b565b611409614bd3565b6040516311c8197f60e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a906311c8197f90610adc906000908690600401615c3c565b600f546001600160a01b0316331461146d5760405162461bcd60e51b81526004016107dc906158ed565b60405163153cc2fd60e31b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063a9e617e890610934906000908590600401615c3c565b60006012546000146114cb5760405162461bcd60e51b81526004016107dc90615857565b600160125560405163758e99b360e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063758e99b390610bf5906000908690600d90600401615a83565b6012541561152d5760405162461bcd60e51b81526004016107dc90615857565b600160125560008061153f8184613064565b63ffffffff1691509150610d12828285600061292b565b6001600160a01b03166000908152600d602052604090205490565b6004546001600160a01b031690565b33301461159f5760405162461bcd60e51b81526004016107dc906158ed565b426202a3006115b6610120850161010086016153bd565b63ffffffff160110156115db5760405162461bcd60e51b81526004016107dc90615947565b600080806116046115ef60208701876153bd565b6115ff6040880160208901615041565b6130a2565b91945092509050600073412da11751b0a36d03b060890f4e41b7ce32971e63a8d669b4600d8560408a01358961164060c08d0160a08e01614e25565b6040518663ffffffff1660e01b8152600401611660959493929190615c4a565b60206040518083038186803b15801561167857600080fd5b505af415801561168c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b09190615355565b9050836001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156116ed57600080fd5b505af1158015611701573d6000803e3d6000fd5b50505050600061172a858861012001358961014001602081019061172591906153bd565b6130de565b90506000806000806000896001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401604080518083038186803b15801561176c57600080fd5b505afa158015611780573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a4919061530b565b915091506117db60018d60200160208101906117c09190615041565b6117ca57826117cc565b835b6001600160701b0316906128ba565b925050506000886001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561181a57600080fd5b505afa15801561182e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118529190614e41565b90506000896001600160a01b03166354cf2aeb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561188f57600080fd5b505afa1580156118a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c79190615355565b9050816001600160a01b031663daab4b6e8d60200160208101906118eb9190615041565b838f606001358a6040518563ffffffff1660e01b815260040161191194939291906157cc565b604080518083038186803b15801561192857600080fd5b505afa15801561193c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611960919061536d565b9095509350600083851115611a265761198760608e01356119818a876131fc565b90613251565b9050826001600160a01b031663a7d208778e60200160208101906119ab9190615041565b84878b6040518563ffffffff1660e01b81526004016119cd94939291906157cc565b604080518083038186803b1580156119e457600080fd5b505afa1580156119f8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1c919061536d565b9096509450611a30565b5060608c01359350865b85811015611a505760405162461bcd60e51b81526004016107dc906159a1565b85881115611ad557600e546001600160a01b038b81169116148015611a805750611a8060a08e0160808f01615041565b15611aaf57611aaa8d60a0016020810190611a9b9190614e25565b611aa58a896128ba565b613281565b611ad5565b611ad58a8e60a0016020810190611ac69190614e25565b611ad08b8a6128ba565b612f10565b611ae08a8c88612f10565b5050506001600160a01b038816600090815260116020526040902054611b0b90839061ffff166128ba565b9150600080611b2060408d0160208e01615041565b15611b2d57839150611b30565b50825b600e546001600160a01b038981169116148015611b585750611b5860a08d0160808e01615041565b15611be15760405163022c0d9f60e01b81526001600160a01b038b169063022c0d9f90611b8f908590859030908c90600401615d4e565b600060405180830381600087803b158015611ba957600080fd5b505af1158015611bbd573d6000803e3d6000fd5b50611bdc9250611bd691505060c08e0160a08f01614e25565b85613281565b611c58565b896001600160a01b031663022c0d9f83838f60a0016020810190611c059190614e25565b8a6040518563ffffffff1660e01b8152600401611c259493929190615d4e565b600060405180830381600087803b158015611c3f57600080fd5b505af1158015611c53573d6000803e3d6000fd5b505050505b505050505050505050505050565b333014611c855760405162461bcd60e51b81526004016107dc906158ed565b611c90838383612f10565b505050565b600080611ca28184612885565b91509150915091565b600f546001600160a01b03163314611cd55760405162461bcd60e51b81526004016107dc906158ed565b60405163b2456a0760e01b8152739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063b2456a0790611d119060009086908690600401615a64565b60006040518083038186803b158015611d2957600080fd5b505af4158015610b61573d6000803e3d6000fd5b60015490565b333014611d625760405162461bcd60e51b81526004016107dc906158ed565b600e546001600160a01b038581169116148015611d7c5750805b15611ea357604051632a359a6d60e21b815260009073412da11751b0a36d03b060890f4e41b7ce32971e9063a8d669b490611dc490600d908990889087908b90600401615c4a565b60206040518083038186803b158015611ddc57600080fd5b505af4158015611df0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e149190615355565b600e54604051632e1a7d4d60e01b81529192506001600160a01b031690632e1a7d4d90611e45908490600401615a27565b600060405180830381600087803b158015611e5f57600080fd5b505af1158015611e73573d6000803e3d6000fd5b5050600080525050600a602052600080516020615e4e83398151915254611e9d90859083906133a1565b50611f3c565b604051632a359a6d60e21b8152611f3c908590859073412da11751b0a36d03b060890f4e41b7ce32971e9063a8d669b490611eec90600d9086908a906000908890600401615c4a565b60206040518083038186803b158015611f0457600080fd5b505af4158015611f18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad09190615355565b50505050565b60006109fa8183613433565b60025490565b333014611f735760405162461bcd60e51b81526004016107dc906158ed565b426202a300611f8a610160860161014087016153bd565b63ffffffff16011015611faf5760405162461bcd60e51b81526004016107dc90615947565b600080600080611fc087878761343c565b92965090945092509050611fda60e0880160c08901615041565b8015611fe557508015155b1561220a57835160009061200b906101608a01356117256101a08c016101808d016153bd565b9050831580159061201c5750816001145b1561210d576000730ec2323adafbebc6c80257c7359692bcceb0b3f163d0b0a9bc87600001518860200151888d60600135601160008d600001516001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a900461ffff16886040518763ffffffff1660e01b81526004016120a796959493929190615739565b604080518083038186803b1580156120be57600080fd5b505af41580156120d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120f6919061536d565b909550905061210584826128ea565b935050612208565b821580159061211c5750816002145b15612208576000730ec2323adafbebc6c80257c7359692bcceb0b3f163adf5f8f387600001518860400151878d60800135601160008d600001516001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a900461ffff16886040518763ffffffff1660e01b81526004016121a796959493929190615739565b604080518083038186803b1580156121be57600080fd5b505af41580156121d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f6919061536d565b9450905061220485826128ea565b9450505b505b821580159061221857508115155b156122d0578351730ec2323adafbebc6c80257c7359692bcceb0b3f190637a528bd29061224c6101008b0160e08c01614e25565b8760200151886040015188886040518763ffffffff1660e01b81526004016122799695949392919061569c565b60606040518083038186803b15801561229157600080fd5b505af41580156122a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c99190615390565b5090935091505b61117f6122e4610100890160e08a01614e25565b856020015186604001518686613780565b601254156123155760405162461bcd60e51b81526004016107dc90615857565b60016012556040517f892cd8f5b436bd5fb7dac1f11aafb73345d892ba3e9fe09cd94d95ba84928e739061234c9033908490615648565b60405180910390a160005a3360009081526010602052604081205491925090819060ff16806123a557506000805260106020527f6e0956cda88cad152e89927e53611735b61a5c762d1428573c6931b0a5efcb015460ff165b905060005b848110156124c5576002546001016000908152600b602052604090205460ff16156123de576123d960006137a2565b6124bd565b6000806123eb60006137ae565b909250905060008260048111156123fe57fe5b148061240a5750428110155b156124165750506124c5565b838061242657506104b081014210155b6124425760405162461bcd60e51b81526004016107dc906158ed565b600194508482600481111561245357fe5b1415612466576124616137d2565b6124ba565b600282600481111561247457fe5b141561248257612461613a22565b600382600481111561249057fe5b141561249e57612461613c26565b60048260048111156124ac57fe5b14156124ba576124ba613e84565b50505b6001016123aa565b50811561254157739cb505f2b41aa426257ed2a0bba005fff0af9e9a639db74df160006124f35a87906128ba565b6040518363ffffffff1660e01b8152600401612510929190615c3c565b60006040518083038186803b15801561252857600080fd5b505af415801561253c573d6000803e3d6000fd5b505050505b505060006012555050565b33301461256b5760405162461bcd60e51b81526004016107dc906158ed565b426202a300612582610120850161010086016153bd565b63ffffffff160110156125a75760405162461bcd60e51b81526004016107dc90615947565b600080806125bb6115ef60208701876153bd565b925092509250826001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156125fc57600080fd5b505af1158015612610573d6000803e3d6000fd5b505050506000612634848761012001358861014001602081019061172591906153bd565b905060006126458787878786613f80565b905060008061265a60408a0160208b01615041565b6126665760008361266a565b8260005b600e5491935091506001600160a01b038681169116148015612697575061269760a08a0160808b01615041565b156127205760405163022c0d9f60e01b81526001600160a01b0388169063022c0d9f906126ce908590859030908a90600401615d4e565b600060405180830381600087803b1580156126e857600080fd5b505af11580156126fc573d6000803e3d6000fd5b5061271b925061271591505060c08b0160a08c01614e25565b84613281565b612794565b6001600160a01b03871663022c0d9f838361274160c08e0160a08f01614e25565b886040518563ffffffff1660e01b81526004016127619493929190615d4e565b600060405180830381600087803b15801561277b57600080fd5b505af115801561278f573d6000803e3d6000fd5b505050505b505050505050505050565b60065490565b600060025b6001600160a01b0383166000908152600c85016020526040902054600160ff9283161b1616151590505b92915050565b600082600101548211156127f0575060006127d4565b6000828152600b8401602052604090205460ff1615612811575060056127d4565b61281b8383614467565b15612828575060046127d4565b6000806128358585612885565b9092509050600082600481111561284857fe5b1415612859576003925050506127d4565b428163ffffffff1610612871576001925050506127d4565b506002949350505050565b600060036127aa565b60008181526003830160205260408120805463ffffffff61010082041691906128b09060ff1661449e565b9250509250929050565b60006128e383836040518060400160405280600481526020016329a6989960e11b81525061450e565b9392505050565b808201828110156127d4576040805162461bcd60e51b81526020600480830191909152602482015263534d344560e01b604482015290519081900360640190fd5b600084600481111561293957fe5b14156129575760405162461bcd60e51b81526004016107dc906159bf565b600042612968856301e133806128ea565b109050600185600481111561297957fe5b1415612ad75760405163117d7ab160e01b8152600090739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063117d7ab1906129bb9084908890600401615c3c565b6101e06040518083038186803b1580156129d457600080fd5b505af41580156129e8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a0c919061514c565b50509050600080612a2b83600001516000612ed790919063ffffffff16565b9250925050600084612a41578360e00151612a4e565b600f546001600160a01b03165b9050612a6a818486602001518588604001518960a001516145a6565b612a865760405162461bcd60e51b81526004016107dc90615893565b8515612ace57612ab281612aad8661012001518761010001516131fc90919063ffffffff16565b614730565b612ace5760405162461bcd60e51b81526004016107dc9061590b565b50505050612ecc565b6002856004811115612ae557fe5b1415612c2b57604051634ce4436960e11b8152600090739cb505f2b41aa426257ed2a0bba005fff0af9e9a906399c886d290612b279084908890600401615c3c565b6101206040518083038186803b158015612b4057600080fd5b505af4158015612b54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b789190615275565b8051909150600090612b8b908290612ed7565b50509050600083612ba0578260a00151612bad565b600f546001600160a01b03165b9050612bc68282856020015163c9cd976060e01b6147b1565b612be25760405162461bcd60e51b81526004016107dc90615893565b8415612c2357612c0781612aad8560e001518660c001516131fc90919063ffffffff16565b612c235760405162461bcd60e51b81526004016107dc9061590b565b505050612ecc565b6003856004811115612c3957fe5b1415612d745760405163ac1ecdb360e01b8152600090739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063ac1ecdb390612c7b9084908890600401615c3c565b6101806040518083038186803b158015612c9457600080fd5b505af4158015612ca8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ccc91906150c7565b509050600080612cea83600001516000612ed790919063ffffffff16565b9250925050600084612d00578360a00151612d0d565b600f546001600160a01b03165b9050612d338460200151612d215783612d23565b825b82866040015187608001516148cc565b612d4f5760405162461bcd60e51b81526004016107dc90615893565b8515612ace57612ab281612aad8660e001518760c001516131fc90919063ffffffff16565b6004856004811115612d8257fe5b1415612ecc576040516311c8197f60e01b8152600090739cb505f2b41aa426257ed2a0bba005fff0af9e9a906311c8197f90612dc49084908890600401615c3c565b6101806040518083038186803b158015612ddd57600080fd5b505af4158015612df1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e1591906150c7565b509050600080612e3383600001516000612ed790919063ffffffff16565b9250925050600084612e49578360a00151612e56565b600f546001600160a01b03165b9050612e6a8460200151612d215783612d23565b612e865760405162461bcd60e51b81526004016107dc90615893565b8515612ec757612eab81612aad8660e001518760c001516131fc90919063ffffffff16565b612ec75760405162461bcd60e51b81526004016107dc9061590b565b505050505b610960600084614918565b63ffffffff166000908152600990910160205260409020805460018201546002909201546001600160a01b039182169392821692911690565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b60208310612f8c5780518252601f199092019160209182019101612f6d565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612fee576040519150601f19603f3d011682016040523d82523d6000602084013e612ff3565b606091505b5091509150818015613021575080511580613021575080806020019051602081101561301e57600080fd5b50515b610960576040805162461bcd60e51b815260206004808301919091526024820152635448303560e01b604482015290519081900360640190fd5b600060016127aa565b6000806130718484614467565b61308d5760405162461bcd60e51b81526004016107dc906159dd565b6130978484612885565b909590945092505050565b600080808080806130b38189612ed7565b925092509250600080886130c85783836130cb565b82845b9598509650939450505050509250925092565b60606000846001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561311b57600080fd5b505afa15801561312f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131539190614e41565b6001600160a01b0316638c09166e85856040518363ffffffff1660e01b8152600401613180929190615da3565b60206040518083038186803b15801561319857600080fd5b505afa1580156131ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131d09190615355565b9050806040516020016131e39190615a27565b6040516020818303038152906040529150509392505050565b60008115806132175750508082028282828161321457fe5b04145b6127d4576040805162461bcd60e51b81526020600480830191909152602482015263534d324160e01b604482015290519081900360640190fd5b600061325d838361495c565b905061326982826131fc565b83146127d45761327a8160016128ea565b90506127d4565b600e54604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906132b1908490600401615a27565b600060405180830381600087803b1580156132cb57600080fd5b505af11580156132df573d6000803e3d6000fd5b50506000808052600a602052600080516020615e4e833981519152546040519193506001600160a01b038616925090849061331990615631565b600060405180830381858888f193505050503d8060008114613357576040519150601f19603f3d011682016040523d82523d6000602084013e61335c565b606091505b5050905080611c905760405163032b310f60e51b815273412da11751b0a36d03b060890f4e41b7ce32971e9063656621e0906112bf90600d9087908790600401615a64565b6040516000906001600160a01b038516908390859084818181858888f193505050503d80600081146133ef576040519150601f19603f3d011682016040523d82523d6000602084013e6133f4565b606091505b5050905080611f3c576040805162461bcd60e51b815260206004808301919091526024820152632a2419a360e11b604482015290519081900360640190fd5b600060046127aa565b613444614cb6565b6000808060098161345860208a018a6153bd565b63ffffffff1663ffffffff1681526020019081526020016000206040518060600160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016002820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152505093506000600d73412da11751b0a36d03b060890f4e41b7ce32971e63a8d669b4909187602001518b602001358b8d60e001602081019061354a9190614e25565b6040518663ffffffff1660e01b815260040161356a959493929190615c4a565b60206040518083038186803b15801561358257600080fd5b505af4158015613596573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ba9190615355565b90506000600d73412da11751b0a36d03b060890f4e41b7ce32971e63a8d669b4909188604001518c604001358b8e60e00160208101906135fa9190614e25565b6040518663ffffffff1660e01b815260040161361a959493929190615c4a565b60206040518083038186803b15801561363257600080fd5b505af4158015613646573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061366a9190615355565b905085600001516001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156136ab57600080fd5b505af11580156136bf573d6000803e3d6000fd5b50508751730ec2323adafbebc6c80257c7359692bcceb0b3f19250637a528bd291506136f26101008d0160e08e01614e25565b89602001518a6040015187876040518763ffffffff1660e01b815260040161371f9695949392919061569c565b60606040518083038186803b15801561373757600080fd5b505af415801561374b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061376f9190615390565b979b919a5098509596505050505050565b811561379157613791848684612f10565b801561096057610960838683612f10565b60020180546001019055565b6000806137c2838460020154600101612885565b90925063ffffffff169050915091565b60005a9050600080600080739cb505f2b41aa426257ed2a0bba005fff0af9e9a63a81df10f90916040518263ffffffff1660e01b81526004016138159190615a27565b6101e06040518083038186803b15801561382e57600080fd5b505af4158015613842573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613866919061514c565b92509250925060008061388785600001516000612ed790919063ffffffff16565b6001600160a01b038082166000908152600a6020526040808220549285168252812054939650919450909250829130916138da916138ce9190610cc49062012c6c906128ea565b6101208a0151906128ba565b6040516378b2847b60e11b906138f8908b908b908b90602401615c85565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516139369190615615565b60006040518083038160008787f1925050503d8060008114613974576040519150601f19603f3d011682016040523d82523d6000602084013e613979565b606091505b5090925090506001826139a7576139a48860e00151868a60200151878c604001518d60a001516145a6565b90505b6139b0816149ac565b6000806139cd8a61012001518b61010001518d8d60e001516149cd565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613a0d939291906157fd565b60405180910390a35050505050505050505050565b60005a6040516313ed2f6160e01b8152909150600090739cb505f2b41aa426257ed2a0bba005fff0af9e9a906313ed2f6190613a62908490600401615a27565b6101206040518083038186803b158015613a7b57600080fd5b505af4158015613a8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ab39190615275565b905060008030613ad6613acb62012c6c61d6d86128ea565b60e0860151906128ba565b604051631a42443160e21b90613af0908790602401615ca7565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613b2e9190615615565b60006040518083038160008787f1925050503d8060008114613b6c576040519150601f19603f3d011682016040523d82523d6000602084013e613b71565b606091505b509092509050600182613bb1578351600090613b8e908290612ed7565b50509050613bad818660a00151876020015163c9cd976060e01b6147b1565b9150505b613bba816149ac565b600080613bd58660e001518760c00151898960a001516149cd565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613c15939291906157fd565b60405180910390a350505050505050565b60005a604051632e9d30e160e01b81529091506000908190739cb505f2b41aa426257ed2a0bba005fff0af9e9a90632e9d30e190613c68908490600401615a27565b6101806040518083038186803b158015613c8157600080fd5b505af4158015613c95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cb991906150c7565b91509150600080613cd884600001516000612ed790919063ffffffff16565b9250925050600080306001600160a01b0316613d37613d2c6000600a0160008a60200151613d065788613d08565b875b6001600160a01b0316815260208101919091526040016000205462012c6c906128ea565b60e0890151906128ba565b604051637f09b54760e11b90613d53908a908a90602401615a0a565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613d919190615615565b60006040518083038160008787f1925050503d8060008114613dcf576040519150601f19603f3d011682016040523d82523d6000602084013e613dd4565b606091505b509092509050600182613e0c57613e098760200151613df35785613df5565b845b8860a0015189604001518a608001516148cc565b90505b613e15816149ac565b600080613e308960e001518a60c001518c8c60a001516149cd565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613e70939291906157fd565b60405180910390a350505050505050505050565b60005a60405163a1ba139560e01b81529091506000908190739cb505f2b41aa426257ed2a0bba005fff0af9e9a9063a1ba139590613ec6908490600401615a27565b6101806040518083038186803b158015613edf57600080fd5b505af4158015613ef3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f1791906150c7565b91509150600080613f3684600001516000612ed790919063ffffffff16565b9250925050600080306001600160a01b0316613f64613d2c6000600a0160008a60200151613d065788613d08565b60405163634e773960e11b90613d53908a908a90602401615a0a565b600080600080866001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401604080518083038186803b158015613fbe57600080fd5b505afa158015613fd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ff6919061530b565b909250905061401060016117c060408c0160208d01615041565b925050506000856001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561404f57600080fd5b505afa158015614063573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140879190614e41565b90506000866001600160a01b03166354cf2aeb6040518163ffffffff1660e01b815260040160206040518083038186803b1580156140c457600080fd5b505afa1580156140d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140fc9190615355565b90506000600d73412da11751b0a36d03b060890f4e41b7ce32971e63a8d669b49091898d604001358d8f60a00160208101906141389190614e25565b6040518663ffffffff1660e01b8152600401614158959493929190615c4a565b60206040518083038186803b15801561417057600080fd5b505af4158015614184573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141a89190615355565b90506141ba60408b0160208c01615041565b614243576040516304a8fad760e31b81526001600160a01b03841690632547d6b8906141ee90859085908b90600401615d7b565b60206040518083038186803b15801561420657600080fd5b505afa15801561421a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061423e9190615355565b6142c3565b60405163c4109d2560e01b81526001600160a01b0384169063c4109d259061427390859085908b90600401615d7b565b60206040518083038186803b15801561428b57600080fd5b505afa15801561429f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142c39190615355565b94506000848611156143fd576142e7866142e160608e0135886131fc565b9061495c565b90506000829050846001600160a01b031663a7d208778d60200160208101906143109190615041565b86898c6040518563ffffffff1660e01b815260040161433294939291906157cc565b604080518083038186803b15801561434957600080fd5b505afa15801561435d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614381919061536d565b600e549098509093506001600160a01b038a811691161480156143af57506143af60a08d0160808e01615041565b156143d6576143d16143c760c08e0160a08f01614e25565b611aa583866128ba565b6143f7565b6143f7898d60a00160208101906143ed9190614e25565b611ad084876128ba565b50614404565b5060608a01355b6001600160a01b03891660009081526011602052604090205461442c90879061ffff166128ba565b95508086101561444e5760405162461bcd60e51b81526004016107dc906158cf565b614459888a84612f10565b505050505095945050505050565b600081815260038301602052604081205465010000000000900460ff166002811480614496575060ff81166003145b949350505050565b600060018214156144b1575060016109fd565b60028214156144c2575060026109fd565b60038214156144d3575060046109fd565b60048214156144e4575060046109fd565b60058214156144f5575060036109fd565b6006821415614506575060036109fd565b506000919050565b818303818482111561459e5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561456357818101518382015260200161454b565b50505050905090810190601f1680156145905780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509392505050565b6001600160a01b038381166000908152600a602052604080822054928816825281205490918291829130916145da916128ea565b604051633ed76f1760e01b906145fe908d908d908d908d908d908d906024016156d6565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161463c9190615615565b60006040518083038160008787f1925050503d806000811461467a576040519150601f19603f3d011682016040523d82523d6000602084013e61467f565b606091505b50915091508161472457876001600160a01b0316896001600160a01b03167f786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b21159289846040516146ce929190615d35565b60405180910390a3856001600160a01b0316896001600160a01b03167f786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b211592878460405161471b929190615d35565b60405180910390a35b50979650505050505050565b60008161473f575060016127d4565b60008052600a602052600080516020615e4e833981519152546147659084908490614a5d565b9050801515836001600160a01b03167fdbef2fc26e7694e7a1c5a4801b1ad144136d149cf76f310a780689b4087f0ffe846040516147a39190615a27565b60405180910390a392915050565b6000826147c057506001614496565b600080306001600160a01b031661d6d88589898960006040516024016147e99493929190615710565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516148279190615615565b60006040518083038160008787f1925050503d8060008114614865576040519150601f19603f3d011682016040523d82523d6000602084013e61486a565b606091505b5091509150816148c257866001600160a01b0316866001600160a01b03167f786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b21159287846040516148b9929190615d35565b60405180910390a35b5095945050505050565b6000826148db57506001614496565b6001600160a01b0385166000908152600a60205260408082205490518291309163e5b1be6560e01b906147e9908b908b908b908b90602401615710565b6000908152600391820160205260408120818155600181018290556002810180546001600160e81b03191690559182015560040180546001600160e01b0319169055565b600080821161499b576040805162461bcd60e51b81526020600480830191909152602482015263534d343360e01b604482015290519081900360640190fd5b8183816149a457fe5b049392505050565b806149c0576149bb6000614abb565b6149ca565b6149ca6000614b0e565b50565b600080806149db87876131fc565b90506149ee615594610cc45a88906128ba565b92506000614a1382614a0e600060060154876131fc90919063ffffffff16565b614b5a565b9050614a1f82826128ba565b9250614a2b3382614730565b614a475760405162461bcd60e51b81526004016107dc9061590b565b614a518584614730565b50505094509492505050565b6040516000906001600160a01b038516908390859084818181858888f193505050503d8060008114614aab576040519150601f19603f3d011682016040523d82523d6000602084013e614ab0565b606091505b509095945050505050565b600281015460009081526003820160205260409020805465010000000000900460ff1615614aea576003614aed565b60025b815460ff91909116650100000000000265ff00000000001990911617905550565b60028082015460009081526003928301602052604081208181556001810182905591820180546001600160e81b03191690559181019190915560040180546001600160e01b0319169055565b6000818310614b6957816128e3565b5090919050565b604051806101200160405280600063ffffffff16815260200160008152602001600081526020016000815260200160001515815260200160006001600160a01b031681526020016000815260200160008152602001600063ffffffff1681525090565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b604051806101a00160405280600063ffffffff1681526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160006001600160a01b031681526020016000815260200160008152602001600063ffffffff16815260200160008152602001600063ffffffff1681525090565b604080516060810182526000808252602082018190529181019190915290565b80356109fd81615e18565b80516109fd81615e18565b80356109fd81615e2d565b80516109fd81615e2d565b60006101608284031215614d14578081fd5b50919050565b6000610160808385031215614d2d578182fd5b614d3681615dc8565b915050614d4282614e1a565b8152614d5060208301614cf7565b60208201526040820151604082015260608201516060820152614d7560808301614cf7565b6080820152614d8660a08301614ce1565b60a082015260c082015160c082015260e082015160e0820152610100614dad818401614e1a565b908201526101208281015190820152610140614dca818401614e1a565b9082015292915050565b60006101008284031215614d14578081fd5b60006101208284031215614d14578081fd5b80516001600160701b03811681146109fd57600080fd5b80356109fd81615e3b565b80516109fd81615e3b565b600060208284031215614e36578081fd5b81356128e381615e18565b600060208284031215614e52578081fd5b81516128e381615e18565b600080600060608486031215614e71578182fd5b8335614e7c81615e18565b92506020840135614e8c81615e18565b929592945050506040919091013590565b60008060008060008060c08789031215614eb5578384fd5b8635614ec081615e18565b95506020870135614ed081615e18565b9450604087013593506060870135614ee781615e18565b92506080870135915060a0870135614efe81615e2d565b809150509295509295509295565b60008060008060808587031215614f21578182fd5b8435614f2c81615e18565b93506020850135614f3c81615e18565b9250604085013591506060850135614f5381615e2d565b939692955090935050565b60008060408385031215614f70578182fd5b8235614f7b81615e18565b91506020830135614f8b81615e2d565b809150509250929050565b600080600060608486031215614faa578081fd5b8335614fb581615e18565b9250602084013560058110614fc8578182fd5b91506040840135614fd881615e2d565b809150509250925092565b60008060408385031215614ff5578182fd5b823561500081615e18565b9150602083013561ffff81168114614f8b578182fd5b60008060408385031215615028578182fd5b823561503381615e18565b946020939093013593505050565b600060208284031215615052578081fd5b81356128e381615e2d565b60008060008060808587031215615072578182fd5b845161507d81615e2d565b60208601516040870151606090970151919890975090945092505050565b60008061018083850312156150ae578182fd5b6150b88484614d02565b94610160939093013593505050565b60008061018083850312156150da578182fd5b6150e48484614d1a565b915061016083015190509250929050565b60006101008284031215615107578081fd5b6128e38383614dd4565b60008060008385036101e0811215615127578182fd5b6101a080821215615136578283fd5b949694870135955050506101c085013592915050565b60008060008385036101e0811215615162578182fd5b6101a080821215615171578283fd5b61517a81615dc8565b915061518586614e1a565b8252602086015160208301526040860151604083015260608601516060830152608086015160808301526151bb60a08701614cf7565b60a08301526151cc60c08701614cf7565b60c08301526151dd60e08701614ce1565b60e083015261010086810151908301526101208087015190830152610140615206818801614e1a565b908301526101608681015190830152610180615223818801614e1a565b908301528501516101c09095015190969495509392505050565b6000610160828403121561524f578081fd5b6128e38383614d02565b6000610120828403121561526b578081fd5b6128e38383614de6565b6000610120808385031215615288578182fd5b61529181615dc8565b905061529c83614e1a565b81526020830151602082015260408301516040820152606083015160608201526152c860808401614cf7565b60808201526152d960a08401614ce1565b60a082015260c083015160c082015260e083015160e0820152610100615300818501614e1a565b908201529392505050565b6000806040838503121561531d578182fd5b61532683614df8565b915061533460208401614df8565b90509250929050565b60006020828403121561534e578081fd5b5035919050565b600060208284031215615366578081fd5b5051919050565b6000806040838503121561537f578182fd5b505080516020909101519092909150565b6000806000606084860312156153a4578081fd5b8351925060208401519150604084015190509250925092565b6000602082840312156153ce578081fd5b81356128e381615e3b565b6001600160a01b03169052565b15159052565b60008151808452615404816020860160208601615dec565b601f01601f19169290920160200192915050565b6005811061542257fe5b9052565b61543182825161560b565b602081015161544360208401826153e6565b506040810151604083015260608101516060830152608081015161546a60808401826153e6565b5060a081015161547d60a08401826153d9565b5060c081015160c083015260e081015160e0830152610100808201516154a58285018261560b565b5050610120818101519083015261014080820151611f3c8285018261560b565b80356154d081615e18565b6001600160a01b0390811683526020820135906154ec82615e18565b1660208301526040818101359083015260608082013590830152608081013561551481615e2d565b1515608083015260a081013561552981615e18565b61553660a08401826153d9565b5060c081013560c083015261554d60e08201614e0f565b611c9060e084018261560b565b61556582825161560b565b6020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015161559f60a08401826153e6565b5060c08101516155b260c08401826153e6565b5060e08101516155c560e08401826153d9565b5061010081810151908301526101208082015190830152610140808201516155ef8285018261560b565b5050610160818101519083015261018080820151611f3c828501825b63ffffffff169052565b60008251615627818460208701615dec565b9190910192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039687168152948616602086015292851660408501529084166060840152909216608082015260a081019190915260c00190565b6001600160a01b0396871681529486166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b6001600160a01b0396871681529486166020860152604085019390935293166060830152608082019290925290151560a082015260c00190565b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b6001600160a01b03878116825286166020820152604081018590526060810184905261ffff8316608082015260c060a0820181905260009061577d908301846153ec565b98975050505050505050565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b0392909216825261ffff16602082015260400190565b901515815260200190565b60008515158252846020830152836040830152608060608301526157f360808301846153ec565b9695505050505050565b60006060825261581060608301866153ec565b60208301949094525060400152919050565b602081016006831061583057fe5b91905290565b604081016158448285615418565b63ffffffff831660208301529392505050565b6020808252600490820152632a22181b60e11b604082015260600190565b6020808252600490820152635444314360e01b604082015260600190565b60208082526004908201526315110c4d60e21b604082015260600190565b6020808252600490820152635444303360e01b604082015260600190565b6020808252600490820152635444333760e01b604082015260600190565b6020808252600490820152630544430360e41b604082015260600190565b6020808252600490820152630544434360e41b604082015260600190565b60208082526004908201526315110d4d60e21b604082015260600190565b60208082526004908201526315110c0d60e21b604082015260600190565b6020808252600490820152632a221a9960e11b604082015260600190565b6020808252600490820152632a22181960e11b604082015260600190565b6020808252600490820152630a88860760e31b604082015260600190565b6020808252600490820152635444343160e01b604082015260600190565b6020808252600490820152634f53323160e01b604082015260600190565b61016081016127d48284615426565b6101808101615a198285615426565b826101608301529392505050565b90815260200190565b8481526001600160a01b038416602082015260808101615a536040830185615418565b821515606083015295945050505050565b9283526001600160a01b03919091166020830152604082015260600190565b8381526101408101615a9860208301856154c5565b82610120830152949350505050565b8381526101a08101615ac460208301615abf86614cd6565b6153d9565b615ad060208501614cd6565b615add60408401826153d9565b506040840135606083015260608401356080830152608084013560a083015260a084013560c0830152615b1260c08501614cec565b615b1f60e08401826153e6565b50615b2c60e08501614cec565b610100615b3b818501836153e6565b615b46818701614cd6565b915050610120615b58818501836153d9565b6101409150808601358285015250615b71818601614e0f565b9050615b8161016084018261560b565b5082610180830152949350505050565b8281526101408101615ba960208301615abf85614cd6565b615bb560208401614cd6565b615bc260408401826153d9565b506040830135606083015260608301356080830152608083013560a0830152615bed60a08401614cec565b615bfa60c08401826153e6565b50615c0760c08401614cd6565b615c1460e08401826153d9565b5061010060e084013581840152615c2c818501614e0f565b905061459e61012084018261560b565b918252602082015260400190565b9485526001600160a01b0393841660208601526040850192909252606084015216608082015260a00190565b6101a081016127d4828461555a565b6101e08101615c94828661555a565b6101a08201939093526101c00152919050565b60006101208201905063ffffffff835116825260208301516020830152604083015160408301526060830151606083015260808301511515608083015260a0830151615cf660a08401826153d9565b5060c083015160c083015260e083015160e083015261010080840151615d1e8285018261560b565b505092915050565b61ffff91909116815260200190565b60008382526040602083015261449660408301846153ec565b600085825284602083015260018060a01b0384166040830152608060608301526157f360808301846153ec565b600084825283602083015260606040830152615d9a60608301846153ec565b95945050505050565b91825263ffffffff16602082015260400190565b63ffffffff91909116815260200190565b60405181810167ffffffffffffffff81118282101715615de457fe5b604052919050565b60005b83811015615e07578181015183820152602001615def565b83811115611f3c5750506000910152565b6001600160a01b03811681146149ca57600080fd5b80151581146149ca57600080fd5b63ffffffff811681146149ca57600080fdfe13da86008ba1c6922daee3e07db95305ef49ebced9f5467a0b8613fcc6b343e3a26469706673582212209aca9082c087ade6eb58f802c44cd779e0548502d9867d5aa9a7369a3e2d997564736f6c63430007060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c6000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000003a1d749fa4a9e650fce844ff1c58c5faf7e2a9d1
-----Decoded View---------------
Arg [0] : _factory (address): 0xC480b33eE5229DE3FbDFAD1D2DCD3F3BAD0C56c6
Arg [1] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [2] : _bot (address): 0x3a1D749fa4a9E650FCe844fF1C58C5faf7e2a9D1
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c6
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [2] : 0000000000000000000000003a1d749fa4a9e650fce844ff1c58c5faf7e2a9d1
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.