Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
Latest 25 from a total of 988 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Execute | 15494383 | 853 days ago | IN | 0 ETH | 0.00327993 | ||||
Withdraw | 15494250 | 853 days ago | IN | 0.02142 ETH | 0.00276691 | ||||
Execute | 15479387 | 855 days ago | IN | 0 ETH | 0.00291172 | ||||
Withdraw | 15479242 | 855 days ago | IN | 0.00916062 ETH | 0.00186664 | ||||
Execute | 15444247 | 861 days ago | IN | 0 ETH | 0.00410485 | ||||
Withdraw | 15444121 | 861 days ago | IN | 0.0091938 ETH | 0.00260976 | ||||
Execute | 15439597 | 862 days ago | IN | 0 ETH | 0.0031472 | ||||
Withdraw | 15439464 | 862 days ago | IN | 0.01112882 ETH | 0.00130193 | ||||
Execute | 15438474 | 862 days ago | IN | 0 ETH | 0.00458451 | ||||
Withdraw | 15438335 | 862 days ago | IN | 0.00935886 ETH | 0.00129324 | ||||
Execute | 15378467 | 871 days ago | IN | 0 ETH | 0.00392788 | ||||
Withdraw | 15378353 | 871 days ago | IN | 0.009408 ETH | 0.00192759 | ||||
Execute | 15361946 | 874 days ago | IN | 0 ETH | 0.00251973 | ||||
Execute | 15361941 | 874 days ago | IN | 0 ETH | 0.00034519 | ||||
Withdraw | 15361812 | 874 days ago | IN | 0.00949158 ETH | 0.00133807 | ||||
Execute | 15343405 | 877 days ago | IN | 0 ETH | 0.0133281 | ||||
Withdraw | 15343280 | 877 days ago | IN | 0.00940044 ETH | 0.00163094 | ||||
Execute | 15337657 | 878 days ago | IN | 0 ETH | 0.00343354 | ||||
Execute | 15337654 | 878 days ago | IN | 0 ETH | 0.00031067 | ||||
Withdraw | 15337537 | 878 days ago | IN | 0.00951132 ETH | 0.00146282 | ||||
Execute | 15337470 | 878 days ago | IN | 0 ETH | 0.01353569 | ||||
Execute | 15337466 | 878 days ago | IN | 0 ETH | 0.00141527 | ||||
Withdraw | 15337334 | 878 days ago | IN | 0.0094164 ETH | 0.00122343 | ||||
Execute | 15337185 | 878 days ago | IN | 0 ETH | 0.00165642 | ||||
Withdraw | 15337056 | 878 days ago | IN | 0.00951048 ETH | 0.001912 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
15494383 | 853 days ago | 0.00359354 ETH | ||||
15494383 | 853 days ago | 0.00508085 ETH | ||||
15494250 | 853 days ago | 0.0127456 ETH | ||||
15479387 | 855 days ago | 0.00340066 ETH | ||||
15479387 | 855 days ago | 0.00532373 ETH | ||||
15479387 | 855 days ago | 12.52682638 ETH | ||||
15479387 | 855 days ago | 12.52682638 ETH | ||||
15479242 | 855 days ago | 0.00043622 ETH | ||||
15444247 | 861 days ago | 0.00302854 ETH | ||||
15444247 | 861 days ago | 0.00572745 ETH | ||||
15444247 | 861 days ago | 0.0537528 ETH | ||||
15444247 | 861 days ago | 0.0537528 ETH | ||||
15444121 | 861 days ago | 0.0004378 ETH | ||||
15439597 | 862 days ago | 0.00364921 ETH | ||||
15439597 | 862 days ago | 0.00694966 ETH | ||||
15439597 | 862 days ago | 59.92119471 ETH | ||||
15439597 | 862 days ago | 59.92119471 ETH | ||||
15439464 | 862 days ago | 0.00052994 ETH | ||||
15438474 | 862 days ago | 0.00094239 ETH | ||||
15438474 | 862 days ago | 0.0079708 ETH | ||||
15438474 | 862 days ago | 59.92119471 ETH | ||||
15438335 | 862 days ago | 0.00044566 ETH | ||||
15378467 | 871 days ago | 0.00262492 ETH | ||||
15378467 | 871 days ago | 0.00633507 ETH | ||||
15378467 | 871 days ago | 9.6226839 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; address public override owner; mapping(address => bool) public override isBot; constructor( address _factory, address _weth, address _bot ) { orders.factory = _factory; owner = msg.sender; isBot[_bot] = true; orders.gasPrice = tx.gasprice - (tx.gasprice % 1e6); tokenShares.setWeth(_weth); orders.delay = 30 minutes; orders.maxGasLimit = 5_000_000; orders.gasPriceInertia = 20_000_000; orders.maxGasPriceImpact = 1_000_000; orders.setTransferGasCost(address(0), Orders.ETHER_TRANSFER_CALL_COST); emit OwnerSet(msg.sender); } function getTransferGasCost(address token) external view override returns (uint256 gasCost) { return orders.transferGasCosts[token]; } function getDepositOrder(uint256 orderId) external view override returns (Orders.DepositOrder memory order) { return orders.getDepositOrder(orderId); } function getWithdrawOrder(uint256 orderId) external view override returns (Orders.WithdrawOrder memory order) { return orders.getWithdrawOrder(orderId); } function getSellOrder(uint256 orderId) external view override returns (Orders.SellOrder memory order) { return orders.getSellOrder(orderId); } function getBuyOrder(uint256 orderId) external view override returns (Orders.BuyOrder memory order) { return orders.getBuyOrder(orderId); } function getDepositDisabled(address pair) external view override returns (bool) { return orders.getDepositDisabled(pair); } function getWithdrawDisabled(address pair) external view override returns (bool) { return orders.getWithdrawDisabled(pair); } function getBuyDisabled(address pair) external view override returns (bool) { return orders.getBuyDisabled(pair); } function getSellDisabled(address pair) external view override returns (bool) { return orders.getSellDisabled(pair); } function getOrderStatus(uint256 orderId) external view override returns (Orders.OrderStatus) { return orders.getOrderStatus(orderId); } uint256 private unlocked = 1; modifier lock() { require(unlocked == 1, 'TD06'); unlocked = 0; _; unlocked = 1; } function factory() external view override returns (address) { return orders.factory; } function totalShares(address token) external view override returns (uint256) { return tokenShares.totalShares[token]; } function weth() external view override returns (address) { return tokenShares.weth; } function delay() external view override returns (uint32) { return orders.delay; } function lastProcessedOrderId() external view returns (uint256) { return orders.lastProcessedOrderId; } function newestOrderId() external view returns (uint256) { return orders.newestOrderId; } function getOrder(uint256 orderId) external view returns (Orders.OrderType orderType, uint32 validAfterTimestamp) { return orders.getOrder(orderId); } function isOrderCanceled(uint256 orderId) external view returns (bool) { return orders.canceled[orderId]; } function maxGasLimit() external view override returns (uint256) { return orders.maxGasLimit; } function maxGasPriceImpact() external view override returns (uint256) { return orders.maxGasPriceImpact; } function gasPriceInertia() external view override returns (uint256) { return orders.gasPriceInertia; } function gasPrice() external view override returns (uint256) { return orders.gasPrice; } function setOrderDisabled( address pair, Orders.OrderType orderType, bool disabled ) external override { require(msg.sender == owner, 'TD00'); orders.setOrderDisabled(pair, orderType, disabled); } function setOwner(address _owner) external override { require(msg.sender == owner, 'TD00'); require(_owner != owner, 'TD01'); require(_owner != address(0), 'TD02'); owner = _owner; emit OwnerSet(_owner); } function setBot(address _bot, bool _isBot) external override { require(msg.sender == owner, 'TD00'); require(_isBot != isBot[_bot], 'TD01'); isBot[_bot] = _isBot; emit BotSet(_bot, _isBot); } function setMaxGasLimit(uint256 _maxGasLimit) external override { require(msg.sender == owner, 'TD00'); orders.setMaxGasLimit(_maxGasLimit); } function setDelay(uint32 _delay) external override { require(msg.sender == owner, 'TD00'); require(_delay != orders.delay, 'TD01'); orders.delay = _delay; emit DelaySet(_delay); } function setGasPriceInertia(uint256 _gasPriceInertia) external override { require(msg.sender == owner, 'TD00'); orders.setGasPriceInertia(_gasPriceInertia); } function setMaxGasPriceImpact(uint256 _maxGasPriceImpact) external override { require(msg.sender == owner, 'TD00'); orders.setMaxGasPriceImpact(_maxGasPriceImpact); } function setTransferGasCost(address token, uint256 gasCost) external override { require(msg.sender == owner, 'TD00'); orders.setTransferGasCost(token, gasCost); } function deposit(Orders.DepositParams calldata depositParams) external payable override lock returns (uint256 orderId) { orders.deposit(depositParams, tokenShares); return orders.newestOrderId; } function withdraw(Orders.WithdrawParams calldata withdrawParams) external payable override lock returns (uint256 orderId) { orders.withdraw(withdrawParams); return orders.newestOrderId; } function sell(Orders.SellParams calldata sellParams) external payable override lock returns (uint256 orderId) { orders.sell(sellParams, tokenShares); return orders.newestOrderId; } function buy(Orders.BuyParams calldata buyParams) external payable override lock returns (uint256 orderId) { orders.buy(buyParams, tokenShares); return orders.newestOrderId; } function execute(uint256 n) external override lock { emit Execute(msg.sender, n); uint256 gasBefore = gasleft(); bool orderExecuted = false; bool senderCanExecute = isBot[msg.sender] || isBot[address(0)]; for (uint256 i = 0; i < n; i++) { if (orders.canceled[orders.lastProcessedOrderId + 1]) { orders.dequeueCanceledOrder(); continue; } (Orders.OrderType orderType, uint256 validAfterTimestamp) = orders.getNextOrder(); if (orderType == Orders.OrderType.Empty || validAfterTimestamp >= block.timestamp) { break; } require(senderCanExecute || block.timestamp >= validAfterTimestamp + BOT_EXECUTION_TIME, 'TD00'); orderExecuted = true; if (orderType == Orders.OrderType.Deposit) { executeDeposit(); } else if (orderType == Orders.OrderType.Withdraw) { executeWithdraw(); } else if (orderType == Orders.OrderType.Sell) { executeSell(); } else if (orderType == Orders.OrderType.Buy) { executeBuy(); } } if (orderExecuted) { orders.updateGasPrice(gasBefore.sub(gasleft())); } } function executeDeposit() internal { uint256 gasStart = gasleft(); Orders.DepositOrder memory depositOrder = orders.dequeueDepositOrder(); (, address token0, address token1) = orders.getPairInfo(depositOrder.pairId); (bool executionSuccess, bytes memory data) = address(this).call{ gas: depositOrder.gasLimit.sub( Orders.ORDER_BASE_COST.add(orders.transferGasCosts[token0]).add(orders.transferGasCosts[token1]) ) }(abi.encodeWithSelector(this._executeDeposit.selector, depositOrder)); bool refundSuccess = true; if (!executionSuccess) { refundSuccess = refundTokens( depositOrder.to, token0, depositOrder.share0, token1, depositOrder.share1, depositOrder.unwrap ); } finalizeOrder(refundSuccess); (uint256 gasUsed, uint256 ethRefund) = refund( depositOrder.gasLimit, depositOrder.gasPrice, gasStart, depositOrder.to ); emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund); } function executeWithdraw() internal { uint256 gasStart = gasleft(); Orders.WithdrawOrder memory withdrawOrder = orders.dequeueWithdrawOrder(); (bool executionSuccess, bytes memory data) = address(this).call{ gas: withdrawOrder.gasLimit.sub(Orders.ORDER_BASE_COST.add(Orders.PAIR_TRANSFER_COST)) }(abi.encodeWithSelector(this._executeWithdraw.selector, withdrawOrder)); bool refundSuccess = true; if (!executionSuccess) { (address pair, , ) = orders.getPairInfo(withdrawOrder.pairId); refundSuccess = refundLiquidity(pair, withdrawOrder.to, withdrawOrder.liquidity); } finalizeOrder(refundSuccess); (uint256 gasUsed, uint256 ethRefund) = refund( withdrawOrder.gasLimit, withdrawOrder.gasPrice, gasStart, withdrawOrder.to ); emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund); } function executeSell() internal { uint256 gasStart = gasleft(); Orders.SellOrder memory sellOrder = orders.dequeueSellOrder(); (, address token0, address token1) = orders.getPairInfo(sellOrder.pairId); (bool executionSuccess, bytes memory data) = address(this).call{ gas: sellOrder.gasLimit.sub( Orders.ORDER_BASE_COST.add(orders.transferGasCosts[sellOrder.inverse ? token1 : token0]) ) }(abi.encodeWithSelector(this._executeSell.selector, sellOrder)); bool refundSuccess = true; if (!executionSuccess) { refundSuccess = refundToken( sellOrder.inverse ? token1 : token0, sellOrder.to, sellOrder.shareIn, sellOrder.unwrap ); } finalizeOrder(refundSuccess); (uint256 gasUsed, uint256 ethRefund) = refund(sellOrder.gasLimit, sellOrder.gasPrice, gasStart, sellOrder.to); emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund); } function executeBuy() internal { uint256 gasStart = gasleft(); Orders.BuyOrder memory buyOrder = orders.dequeueBuyOrder(); (, address token0, address token1) = orders.getPairInfo(buyOrder.pairId); (bool executionSuccess, bytes memory data) = address(this).call{ gas: buyOrder.gasLimit.sub( Orders.ORDER_BASE_COST.add(orders.transferGasCosts[buyOrder.inverse ? token1 : token0]) ) }(abi.encodeWithSelector(this._executeBuy.selector, buyOrder)); bool refundSuccess = true; if (!executionSuccess) { refundSuccess = refundToken( buyOrder.inverse ? token1 : token0, buyOrder.to, buyOrder.shareInMax, buyOrder.unwrap ); } finalizeOrder(refundSuccess); (uint256 gasUsed, uint256 ethRefund) = refund(buyOrder.gasLimit, buyOrder.gasPrice, gasStart, buyOrder.to); emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund); } function finalizeOrder(bool refundSuccess) private { if (!refundSuccess) { orders.markRefundFailed(); } else { orders.forgetLastProcessedOrder(); } } function refund( uint256 gasLimit, uint256 gasPriceInOrder, uint256 gasStart, address to ) private returns (uint256 gasUsed, uint256 leftOver) { uint256 feeCollected = gasLimit.mul(gasPriceInOrder); gasUsed = gasStart.sub(gasleft()).add(Orders.REFUND_BASE_COST); uint256 actualRefund = Math.min(feeCollected, gasUsed.mul(orders.gasPrice)); leftOver = feeCollected.sub(actualRefund); require(refundEth(msg.sender, actualRefund), 'TD40'); refundEth(payable(to), leftOver); } function refundEth(address payable to, uint256 value) internal returns (bool success) { if (value == 0) { return true; } success = TransferHelper.transferETH(to, value, orders.transferGasCosts[address(0)]); emit EthRefund(to, success, value); } function refundToken( address token, address to, uint256 share, bool unwrap ) private returns (bool) { if (share == 0) { return true; } (bool success, bytes memory data) = address(this).call{ gas: orders.transferGasCosts[token] }( abi.encodeWithSelector(this._refundToken.selector, token, to, share, unwrap) ); if (!success) { emit RefundFailed(to, token, share, data); } return success; } function refundTokens( address to, address token0, uint256 share0, address token1, uint256 share1, bool unwrap ) private returns (bool) { (bool success, bytes memory data) = address(this).call{ gas: orders.transferGasCosts[token0].add(orders.transferGasCosts[token1]) }(abi.encodeWithSelector(this._refundTokens.selector, to, token0, share0, token1, share1, unwrap)); if (!success) { emit RefundFailed(to, token0, share0, data); emit RefundFailed(to, token1, share1, data); } return success; } function _refundTokens( address to, address token0, uint256 share0, address token1, uint256 share1, bool unwrap ) external { // no need to check sender, because it is checked in _refundToken _refundToken(token0, to, share0, unwrap); _refundToken(token1, to, share1, unwrap); } function _refundToken( address token, address to, uint256 share, bool unwrap ) public { require(msg.sender == address(this), 'TD00'); if (token == tokenShares.weth && unwrap) { uint256 amount = tokenShares.sharesToAmount(token, share); IWETH(tokenShares.weth).withdraw(amount); TransferHelper.safeTransferETH(to, amount, orders.transferGasCosts[address(0)]); } else { TransferHelper.safeTransfer(token, to, tokenShares.sharesToAmount(token, share)); } } function refundLiquidity( address pair, address to, uint256 liquidity ) private returns (bool) { if (liquidity == 0) { return true; } (bool success, bytes memory data) = address(this).call{ gas: Orders.PAIR_TRANSFER_COST }( abi.encodeWithSelector(this._refundLiquidity.selector, pair, to, liquidity, false) ); if (!success) { emit RefundFailed(to, pair, liquidity, data); } return success; } function _refundLiquidity( address pair, address to, uint256 liquidity ) external { require(msg.sender == address(this), 'TD00'); return TransferHelper.safeTransfer(pair, to, liquidity); } function _executeDeposit(Orders.DepositOrder memory depositOrder) external { require(msg.sender == address(this), 'TD00'); require(depositOrder.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04'); (address pair, address token0, address token1, uint256 amount0Left, uint256 amount1Left) = _initialDeposit( depositOrder ); if (depositOrder.swap) { if (amount0Left != 0) { (amount0Left, amount1Left) = AddLiquidity.swapDeposit0( pair, token0, amount0Left, depositOrder.minSwapPrice, encodePriceInfo(pair, depositOrder.priceAccumulator, depositOrder.timestamp) ); } else if (amount1Left != 0) { (amount0Left, amount1Left) = AddLiquidity.swapDeposit1( pair, token1, amount1Left, depositOrder.maxSwapPrice, encodePriceInfo(pair, depositOrder.priceAccumulator, depositOrder.timestamp) ); } } if (amount0Left != 0 && amount1Left != 0) { (amount0Left, amount1Left) = AddLiquidity.addLiquidityAndMint( pair, depositOrder.to, token0, token1, amount0Left, amount1Left ); } _refundDeposit(depositOrder.to, token0, token1, amount0Left, amount1Left); } function _initialDeposit(Orders.DepositOrder memory depositOrder) private returns ( address pair, address token0, address token1, uint256 amount0Left, uint256 amount1Left ) { (pair, token0, token1) = orders.getPairInfo(depositOrder.pairId); uint256 amount0Desired = tokenShares.sharesToAmount(token0, depositOrder.share0); uint256 amount1Desired = tokenShares.sharesToAmount(token1, depositOrder.share1); ITwapPair(pair).sync(); (amount0Left, amount1Left) = AddLiquidity.addLiquidityAndMint( pair, depositOrder.to, token0, token1, amount0Desired, amount1Desired ); } function _refundDeposit( address to, address token0, address token1, uint256 amount0, uint256 amount1 ) private { if (amount0 > 0) { TransferHelper.safeTransfer(token0, to, amount0); } if (amount1 > 0) { TransferHelper.safeTransfer(token1, to, amount1); } } function _executeWithdraw(Orders.WithdrawOrder memory withdrawOrder) external { require(msg.sender == address(this), 'TD00'); require(withdrawOrder.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04'); (address pair, address token0, address token1) = orders.getPairInfo(withdrawOrder.pairId); ITwapPair(pair).sync(); TransferHelper.safeTransfer(pair, pair, withdrawOrder.liquidity); (uint256 wethAmount, uint256 amount0, uint256 amount1) = (0, 0, 0); if (withdrawOrder.unwrap && (token0 == tokenShares.weth || token1 == tokenShares.weth)) { bool success; (success, wethAmount, amount0, amount1) = WithdrawHelper.withdrawAndUnwrap( token0, token1, pair, tokenShares.weth, withdrawOrder.to, orders.transferGasCosts[address(0)] ); if (!success) { tokenShares.onUnwrapFailed(withdrawOrder.to, wethAmount); } } else { (amount0, amount1) = ITwapPair(pair).burn(withdrawOrder.to); } require(amount0 >= withdrawOrder.amount0Min && amount1 >= withdrawOrder.amount1Min, 'TD03'); } function _executeBuy(Orders.BuyOrder memory buyOrder) external { require(msg.sender == address(this), 'TD00'); require(buyOrder.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04'); (address pairAddress, address tokenIn, address tokenOut) = _getPairAndTokens(buyOrder.pairId, buyOrder.inverse); uint256 amountInMax = tokenShares.sharesToAmount(tokenIn, buyOrder.shareInMax); ITwapPair pair = ITwapPair(pairAddress); pair.sync(); bytes memory priceInfo = encodePriceInfo(pairAddress, buyOrder.priceAccumulator, buyOrder.timestamp); uint256 amountIn = buyOrder.inverse ? pair.getSwapAmount1In(buyOrder.amountOut, priceInfo) : pair.getSwapAmount0In(buyOrder.amountOut, priceInfo); require(amountInMax >= amountIn, 'TD08'); if (amountInMax > amountIn) { if (tokenIn == tokenShares.weth && buyOrder.unwrap) { _forceEtherTransfer(buyOrder.to, amountInMax.sub(amountIn)); } else { TransferHelper.safeTransfer(tokenIn, buyOrder.to, amountInMax.sub(amountIn)); } } (uint256 amount0Out, uint256 amount1Out) = buyOrder.inverse ? (buyOrder.amountOut, uint256(0)) : (uint256(0), buyOrder.amountOut); TransferHelper.safeTransfer(tokenIn, pairAddress, amountIn); if (tokenOut == tokenShares.weth && buyOrder.unwrap) { pair.swap(amount0Out, amount1Out, address(this), priceInfo); _forceEtherTransfer(buyOrder.to, buyOrder.amountOut); } else { pair.swap(amount0Out, amount1Out, buyOrder.to, priceInfo); } } function _executeSell(Orders.SellOrder memory sellOrder) external { require(msg.sender == address(this), 'TD00'); require(sellOrder.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04'); (address pairAddress, address tokenIn, address tokenOut) = _getPairAndTokens( sellOrder.pairId, sellOrder.inverse ); uint256 amountIn = tokenShares.sharesToAmount(tokenIn, sellOrder.shareIn); ITwapPair pair = ITwapPair(pairAddress); pair.sync(); bytes memory priceInfo = encodePriceInfo(pairAddress, sellOrder.priceAccumulator, sellOrder.timestamp); uint256 amountOut = sellOrder.inverse ? pair.getSwapAmount0Out(amountIn, priceInfo) : pair.getSwapAmount1Out(amountIn, priceInfo); require(amountOut >= sellOrder.amountOutMin, 'TD37'); (uint256 amount0Out, uint256 amount1Out) = sellOrder.inverse ? (amountOut, uint256(0)) : (uint256(0), amountOut); TransferHelper.safeTransfer(tokenIn, pairAddress, amountIn); if (tokenOut == tokenShares.weth && sellOrder.unwrap) { pair.swap(amount0Out, amount1Out, address(this), priceInfo); _forceEtherTransfer(sellOrder.to, amountOut); } else { pair.swap(amount0Out, amount1Out, sellOrder.to, priceInfo); } } function _getPairAndTokens(uint32 pairId, bool pairInversed) private view returns ( address, address, address ) { (address pairAddress, address token0, address token1) = orders.getPairInfo(pairId); (address tokenIn, address tokenOut) = pairInversed ? (token1, token0) : (token0, token1); return (pairAddress, tokenIn, tokenOut); } function _forceEtherTransfer(address to, uint256 amount) internal { IWETH(tokenShares.weth).withdraw(amount); (bool success, ) = to.call{ value: amount, gas: orders.transferGasCosts[address(0)] }(''); if (!success) { tokenShares.onUnwrapFailed(to, amount); } } function performRefund( Orders.OrderType orderType, uint256 validAfterTimestamp, uint256 orderId, bool shouldRefundEth ) internal { require(orderType != Orders.OrderType.Empty, 'TD41'); bool canOwnerRefund = validAfterTimestamp.add(365 days) < block.timestamp; if (orderType == Orders.OrderType.Deposit) { Orders.DepositOrder memory depositOrder = orders.getDepositOrder(orderId); (, address token0, address token1) = orders.getPairInfo(depositOrder.pairId); address to = canOwnerRefund ? owner : depositOrder.to; require( refundTokens(to, token0, depositOrder.share0, token1, depositOrder.share1, depositOrder.unwrap), 'TD14' ); if (shouldRefundEth) { uint256 value = depositOrder.gasPrice.mul(depositOrder.gasLimit); require(refundEth(payable(to), value), 'TD40'); } } else if (orderType == Orders.OrderType.Withdraw) { Orders.WithdrawOrder memory withdrawOrder = orders.getWithdrawOrder(orderId); (address pair, , ) = orders.getPairInfo(withdrawOrder.pairId); address to = canOwnerRefund ? owner : withdrawOrder.to; require(refundLiquidity(pair, to, withdrawOrder.liquidity), 'TD14'); if (shouldRefundEth) { uint256 value = withdrawOrder.gasPrice.mul(withdrawOrder.gasLimit); require(refundEth(payable(to), value), 'TD40'); } } else if (orderType == Orders.OrderType.Sell) { Orders.SellOrder memory sellOrder = orders.getSellOrder(orderId); (, address token0, address token1) = orders.getPairInfo(sellOrder.pairId); address to = canOwnerRefund ? owner : sellOrder.to; require(refundToken(sellOrder.inverse ? token1 : token0, to, sellOrder.shareIn, sellOrder.unwrap), 'TD14'); if (shouldRefundEth) { uint256 value = sellOrder.gasPrice.mul(sellOrder.gasLimit); require(refundEth(payable(to), value), 'TD40'); } } else if (orderType == Orders.OrderType.Buy) { Orders.BuyOrder memory buyOrder = orders.getBuyOrder(orderId); (, address token0, address token1) = orders.getPairInfo(buyOrder.pairId); address to = canOwnerRefund ? owner : buyOrder.to; require(refundToken(buyOrder.inverse ? token1 : token0, to, buyOrder.shareInMax, buyOrder.unwrap), 'TD14'); if (shouldRefundEth) { uint256 value = buyOrder.gasPrice.mul(buyOrder.gasLimit); require(refundEth(payable(to), value), 'TD40'); } } orders.forgetOrder(orderId); } function retryRefund(uint256 orderId) external override lock { (Orders.OrderType orderType, uint256 validAfterTimestamp) = orders.getFailedOrderType(orderId); performRefund(orderType, validAfterTimestamp, orderId, false); } function cancelOrder(uint256 orderId) external override lock { require(orders.getOrderStatus(orderId) == Orders.OrderStatus.EnqueuedReady, 'TD52'); (Orders.OrderType orderType, uint256 validAfterTimestamp) = orders.getOrder(orderId); require(validAfterTimestamp.sub(orders.delay).add(ORDER_CANCEL_TIME) < block.timestamp, 'TD1C'); orders.canceled[orderId] = true; performRefund(orderType, validAfterTimestamp, orderId, true); } function encodePriceInfo( address pair, uint256 priceAccumulator, uint32 priceTimestamp ) internal view returns (bytes memory data) { uint256 price = ITwapOracle(ITwapPair(pair).oracle()).getAveragePrice(priceAccumulator, priceTimestamp); // Pack everything as 32 bytes / uint256 to simplify decoding data = abi.encode(price); } receive() external payable {} }
// 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; import './interfaces/ITwapOracle.sol'; import './interfaces/IERC20.sol'; import './libraries/SafeMath.sol'; import '@uniswap/v2-periphery/contracts/libraries/UniswapV2OracleLibrary.sol'; contract TwapOracle is ITwapOracle { using SafeMath for uint256; using SafeMath for int256; uint8 public immutable override xDecimals; uint8 public immutable override yDecimals; int256 public immutable override decimalsConverter; address public override owner; address public override uniswapPair; constructor(uint8 _xDecimals, uint8 _yDecimals) { require(_xDecimals <= 75 && _yDecimals <= 75, 'TO4F'); if (_yDecimals > _xDecimals) { require(_yDecimals - _xDecimals <= 18, 'TO47'); } else { require(_xDecimals - _yDecimals <= 18, 'TO47'); } owner = msg.sender; xDecimals = _xDecimals; yDecimals = _yDecimals; decimalsConverter = (10**(18 + _xDecimals - _yDecimals)).toInt256(); emit OwnerSet(msg.sender); } function isContract(address addr) private view returns (bool) { uint256 size; assembly { size := extcodesize(addr) } return size > 0; } function setOwner(address _owner) external override { require(msg.sender == owner, 'TO00'); require(_owner != address(0), 'TO02'); require(_owner != owner, 'TO01'); owner = _owner; emit OwnerSet(_owner); } function setUniswapPair(address _uniswapPair) external override { require(msg.sender == owner, 'TO00'); require(_uniswapPair != uniswapPair, 'TO01'); require(_uniswapPair != address(0), 'TO02'); require(isContract(_uniswapPair), 'TO0B'); uniswapPair = _uniswapPair; IUniswapV2Pair pairContract = IUniswapV2Pair(_uniswapPair); require( IERC20(pairContract.token0()).decimals() == xDecimals && IERC20(pairContract.token1()).decimals() == yDecimals, 'TO45' ); (uint112 reserve0, uint112 reserve1, ) = pairContract.getReserves(); require(reserve0 != 0 && reserve1 != 0, 'TO1F'); emit UniswapPairSet(_uniswapPair); } // based on: https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2OracleLibrary.sol function getPriceInfo() public view override returns (uint256 priceAccumulator, uint32 priceTimestamp) { IUniswapV2Pair pair = IUniswapV2Pair(uniswapPair); priceAccumulator = pair.price0CumulativeLast(); (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = pair.getReserves(); // uint32 can be cast directly until Sun, 07 Feb 2106 06:28:15 GMT priceTimestamp = uint32(block.timestamp); if (blockTimestampLast != priceTimestamp) { // allow overflow to stay consistent with Uniswap code and save some gas uint32 timeElapsed = priceTimestamp - blockTimestampLast; priceAccumulator += uint256(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed; } } function decodePriceInfo(bytes memory data) internal pure returns (uint256 price) { assembly { price := mload(add(data, 32)) } } function getSpotPrice() external view override returns (uint256) { (uint112 reserve0, uint112 reserve1, ) = IUniswapV2Pair(uniswapPair).getReserves(); return uint256(reserve1).mul(uint256(decimalsConverter)).div(uint256(reserve0)); } function getAveragePrice(uint256 priceAccumulator, uint32 priceTimestamp) public view override returns (uint256) { (uint256 currentPriceAccumulator, uint32 currentPriceTimestamp) = getPriceInfo(); require(priceTimestamp < currentPriceTimestamp, 'TO20'); // timeElapsed = currentPriceTimestamp - priceTimestamp (overflow is desired) // averagePrice = (currentPriceAccumulator - priceAccumulator) / timeElapsed // return value = (averagePrice * decimalsConverter) / 2**112 return ((currentPriceAccumulator - priceAccumulator) / (currentPriceTimestamp - priceTimestamp)).mul( uint256(decimalsConverter) ) >> 112; } function tradeX( uint256 xAfter, uint256 xBefore, uint256 yBefore, bytes calldata data ) external view override returns (uint256 yAfter) { int256 xAfterInt = xAfter.toInt256(); int256 xBeforeInt = xBefore.toInt256(); int256 yBeforeInt = yBefore.toInt256(); int256 averagePriceInt = decodePriceInfo(data).toInt256(); int256 yTradedInt = xAfterInt.sub(xBeforeInt).mul(averagePriceInt); // yAfter = yBefore - yTraded = yBefore - ((xAfter - xBefore) * price) // we are multiplying yBefore by decimalsConverter to push division to the very end int256 yAfterInt = yBeforeInt.mul(decimalsConverter).sub(yTradedInt).div(decimalsConverter); require(yAfterInt >= 0, 'TO27'); yAfter = uint256(yAfterInt); } function tradeY( uint256 yAfter, uint256 xBefore, uint256 yBefore, bytes calldata data ) external view override returns (uint256 xAfter) { int256 yAfterInt = yAfter.toInt256(); int256 xBeforeInt = xBefore.toInt256(); int256 yBeforeInt = yBefore.toInt256(); int256 averagePriceInt = decodePriceInfo(data).toInt256(); int256 xTradedInt = yAfterInt.sub(yBeforeInt).mul(decimalsConverter); // xAfter = xBefore - xTraded = xBefore - ((yAfter - yBefore) * price) // we are multiplying xBefore by averagePriceInt to push division to the very end int256 xAfterInt = xBeforeInt.mul(averagePriceInt).sub(xTradedInt).div(averagePriceInt); require(xAfterInt >= 0, 'TO28'); xAfter = uint256(xAfterInt); } function depositTradeXIn( uint256 xLeft, uint256 xBefore, uint256 yBefore, bytes calldata data ) external view override returns (uint256) { if (xBefore == 0 || yBefore == 0) { return 0; } // ratio after swap = ratio after second mint // (xBefore + xIn) / (yBefore - xIn * price) = (xBefore + xLeft) / yBefore // xIn = xLeft * yBefore / (price * (xLeft + xBefore) + yBefore) uint256 price = decodePriceInfo(data); uint256 numerator = xLeft.mul(yBefore); uint256 denominator = price.mul(xLeft.add(xBefore)).add(yBefore.mul(uint256(decimalsConverter))); uint256 xIn = numerator.mul(uint256(decimalsConverter)).div(denominator); // Don't swap when numbers are too large. This should actually never happen. if (xIn.mul(price).div(uint256(decimalsConverter)) >= yBefore || xIn >= xLeft) { return 0; } return xIn; } function depositTradeYIn( uint256 yLeft, uint256 xBefore, uint256 yBefore, bytes calldata data ) external view override returns (uint256) { if (xBefore == 0 || yBefore == 0) { return 0; } // ratio after swap = ratio after second mint // (xBefore - yIn / price) / (yBefore + yIn) = xBefore / (yBefore + yLeft) // yIn = price * xBefore * yLeft / (price * xBefore + yLeft + yBefore) uint256 price = decodePriceInfo(data); uint256 numerator = price.mul(xBefore).mul(yLeft); uint256 denominator = price.mul(xBefore).add(yLeft.add(yBefore).mul(uint256(decimalsConverter))); uint256 yIn = numerator.div(denominator); // Don't swap when numbers are too large. This should actually never happen. if (yIn.mul(uint256(decimalsConverter)).div(price) >= xBefore || yIn >= yLeft) { return 0; } return yIn; } }
// 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); }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) library SafeMath { int256 private constant _INT256_MIN = -2**255; function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x, 'SM4E'); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { z = sub(x, y, 'SM12'); } function sub( uint256 x, uint256 y, string memory message ) internal pure returns (uint256 z) { require((z = x - y) <= x, message); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x, 'SM2A'); } function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, 'SM43'); uint256 c = a / b; return c; } function ceil_div(uint256 a, uint256 b) internal pure returns (uint256 c) { c = div(a, b); if (c == mul(a, b)) { return c; } else { return add(c, 1); } } function toUint32(uint256 n) internal pure returns (uint32) { require(n <= type(uint32).max, 'SM50'); return uint32(n); } function toUint112(uint256 n) internal pure returns (uint112) { require(n <= type(uint112).max, 'SM51'); return uint112(n); } function toInt256(uint256 unsigned) internal pure returns (int256 signed) { require(unsigned <= uint256(type(int256).max), 'SM34'); signed = int256(unsigned); } // int256 function add(int256 a, int256 b) internal pure returns (int256) { int256 c = a + b; require((b >= 0 && c >= a) || (b < 0 && c < a), 'SM4D'); return c; } function sub(int256 a, int256 b) internal pure returns (int256) { int256 c = a - b; require((b >= 0 && c <= a) || (b < 0 && c > a), 'SM11'); return c; } function mul(int256 a, int256 b) internal pure returns (int256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } require(!(a == -1 && b == _INT256_MIN), 'SM29'); int256 c = a * b; require(c / a == b, 'SM29'); return c; } function div(int256 a, int256 b) internal pure returns (int256) { require(b != 0, 'SM43'); require(!(b == -1 && a == _INT256_MIN), 'SM42'); int256 c = a / b; return c; } }
pragma solidity >=0.5.0; import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol'; import '@uniswap/lib/contracts/libraries/FixedPoint.sol'; // library with helper methods for oracles that are concerned with computing average prices library UniswapV2OracleLibrary { using FixedPoint for *; // helper function that returns the current block timestamp within the range of uint32, i.e. [0, 2**32 - 1] function currentBlockTimestamp() internal view returns (uint32) { return uint32(block.timestamp % 2 ** 32); } // produces the cumulative price using counterfactuals to save gas and avoid a call to sync. function currentCumulativePrices( address pair ) internal view returns (uint price0Cumulative, uint price1Cumulative, uint32 blockTimestamp) { blockTimestamp = currentBlockTimestamp(); price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast(); price1Cumulative = IUniswapV2Pair(pair).price1CumulativeLast(); // if time has elapsed since the last update on the pair, mock the accumulated price values (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = IUniswapV2Pair(pair).getReserves(); if (blockTimestampLast != blockTimestamp) { // subtraction overflow is desired uint32 timeElapsed = blockTimestamp - blockTimestampLast; // addition overflow is desired // counterfactual price0Cumulative += uint(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed; // counterfactual price1Cumulative += uint(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed; } } }
pragma solidity >=0.5.0; interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; function initialize(address, address) external; }
pragma solidity >=0.4.0; // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) library FixedPoint { // range: [0, 2**112 - 1] // resolution: 1 / 2**112 struct uq112x112 { uint224 _x; } // range: [0, 2**144 - 1] // resolution: 1 / 2**112 struct uq144x112 { uint _x; } uint8 private constant RESOLUTION = 112; // encode a uint112 as a UQ112x112 function encode(uint112 x) internal pure returns (uq112x112 memory) { return uq112x112(uint224(x) << RESOLUTION); } // encodes a uint144 as a UQ144x112 function encode144(uint144 x) internal pure returns (uq144x112 memory) { return uq144x112(uint256(x) << RESOLUTION); } // divide a UQ112x112 by a uint112, returning a UQ112x112 function div(uq112x112 memory self, uint112 x) internal pure returns (uq112x112 memory) { require(x != 0, 'FixedPoint: DIV_BY_ZERO'); return uq112x112(self._x / uint224(x)); } // multiply a UQ112x112 by a uint, returning a UQ144x112 // reverts on overflow function mul(uq112x112 memory self, uint y) internal pure returns (uq144x112 memory) { uint z; require(y == 0 || (z = uint(self._x) * y) / y == uint(self._x), "FixedPoint: MULTIPLICATION_OVERFLOW"); return uq144x112(z); } // returns a UQ112x112 which represents the ratio of the numerator to the denominator // equivalent to encode(numerator).div(denominator) function fraction(uint112 numerator, uint112 denominator) internal pure returns (uq112x112 memory) { require(denominator > 0, "FixedPoint: DIV_BY_ZERO"); return uq112x112((uint224(numerator) << RESOLUTION) / denominator); } // decode a UQ112x112 into a uint112 by truncating after the radix point function decode(uq112x112 memory self) internal pure returns (uint112) { return uint112(self._x >> RESOLUTION); } // decode a UQ144x112 into a uint144 by truncating after the radix point function decode144(uq144x112 memory self) internal pure returns (uint144) { return uint144(self._x >> RESOLUTION); } }
// 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 '../libraries/Orders.sol'; interface ITwapDelay { event OrderExecuted(uint256 indexed id, bool indexed success, bytes data, uint256 gasSpent, uint256 ethRefunded); event RefundFailed(address indexed to, address indexed token, uint256 amount, bytes data); event EthRefund(address indexed to, bool indexed success, uint256 value); event OwnerSet(address owner); event BotSet(address bot, bool isBot); event DelaySet(uint256 delay); event MaxGasLimitSet(uint256 maxGasLimit); event GasPriceInertiaSet(uint256 gasPriceInertia); event MaxGasPriceImpactSet(uint256 maxGasPriceImpact); event TransferGasCostSet(address token, uint256 gasCost); event OrderDisabled(address pair, Orders.OrderType orderType, bool disabled); event UnwrapFailed(address to, uint256 amount); event Execute(address sender, uint256 n); function factory() external returns (address); function owner() external returns (address); function isBot(address bot) external returns (bool); function gasPriceInertia() external returns (uint256); function gasPrice() external returns (uint256); function maxGasPriceImpact() external returns (uint256); function maxGasLimit() external returns (uint256); function delay() external returns (uint32); function totalShares(address token) external returns (uint256); function weth() external returns (address); function getTransferGasCost(address token) external returns (uint256); function getDepositOrder(uint256 orderId) external returns (Orders.DepositOrder memory order); function getWithdrawOrder(uint256 orderId) external returns (Orders.WithdrawOrder memory order); function getSellOrder(uint256 orderId) external returns (Orders.SellOrder memory order); function getBuyOrder(uint256 orderId) external returns (Orders.BuyOrder memory order); function getDepositDisabled(address pair) external returns (bool); function getWithdrawDisabled(address pair) external returns (bool); function getBuyDisabled(address pair) external returns (bool); function getSellDisabled(address pair) external returns (bool); function getOrderStatus(uint256 orderId) external returns (Orders.OrderStatus); function setOrderDisabled( address pair, Orders.OrderType orderType, bool disabled ) external; function setOwner(address _owner) external; function setBot(address _bot, bool _isBot) external; function setMaxGasLimit(uint256 _maxGasLimit) external; function setDelay(uint32 _delay) external; function setGasPriceInertia(uint256 _gasPriceInertia) external; function setMaxGasPriceImpact(uint256 _maxGasPriceImpact) external; function setTransferGasCost(address token, uint256 gasCost) external; function deposit(Orders.DepositParams memory depositParams) external payable returns (uint256 orderId); function withdraw(Orders.WithdrawParams memory withdrawParams) external payable returns (uint256 orderId); function sell(Orders.SellParams memory sellParams) external payable returns (uint256 orderId); function buy(Orders.BuyParams memory buyParams) external payable returns (uint256 orderId); function execute(uint256 n) external; function retryRefund(uint256 orderId) external; function cancelOrder(uint256 orderId) external; }
// 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; pragma abicoder v2; import './SafeMath.sol'; import '../libraries/Math.sol'; import '../interfaces/ITwapFactory.sol'; import '../interfaces/ITwapPair.sol'; import '../interfaces/ITwapOracle.sol'; import '../libraries/TokenShares.sol'; library Orders { using SafeMath for uint256; using TokenShares for TokenShares.Data; using TransferHelper for address; enum OrderType { Empty, Deposit, Withdraw, Sell, Buy } enum OrderStatus { NonExistent, EnqueuedWaiting, EnqueuedReady, ExecutedSucceeded, ExecutedFailed, Canceled } event MaxGasLimitSet(uint256 maxGasLimit); event GasPriceInertiaSet(uint256 gasPriceInertia); event MaxGasPriceImpactSet(uint256 maxGasPriceImpact); event TransferGasCostSet(address token, uint256 gasCost); event DepositEnqueued(uint256 indexed orderId, uint32 validAfterTimestamp, uint256 gasPrice); event WithdrawEnqueued(uint256 indexed orderId, uint32 validAfterTimestamp, uint256 gasPrice); event SellEnqueued(uint256 indexed orderId, uint32 validAfterTimestamp, uint256 gasPrice); event BuyEnqueued(uint256 indexed orderId, uint32 validAfterTimestamp, uint256 gasPrice); event OrderDisabled(address pair, Orders.OrderType orderType, bool disabled); uint8 private constant DEPOSIT_TYPE = 1; uint8 private constant WITHDRAW_TYPE = 2; uint8 private constant BUY_TYPE = 3; uint8 private constant BUY_INVERTED_TYPE = 4; uint8 private constant SELL_TYPE = 5; uint8 private constant SELL_INVERTED_TYPE = 6; uint8 private constant UNWRAP_NOT_FAILED = 0; uint8 private constant KEEP_NOT_FAILED = 1; uint8 private constant UNWRAP_FAILED = 2; uint8 private constant KEEP_FAILED = 3; uint256 private constant ETHER_TRANSFER_COST = 2600 + 1504; // EIP-2929 acct access cost + Gnosis Safe receive ETH cost uint256 private constant BUFFER_COST = 10000; uint256 private constant ORDER_EXECUTED_EVENT_COST = 3700; uint256 private constant EXECUTE_PREPARATION_COST = 55000; // dequeue + getPair in execute uint256 public constant ETHER_TRANSFER_CALL_COST = 10000; uint256 public constant PAIR_TRANSFER_COST = 55000; uint256 public constant REFUND_BASE_COST = 2 * ETHER_TRANSFER_COST + BUFFER_COST + ORDER_EXECUTED_EVENT_COST; uint256 public constant ORDER_BASE_COST = EXECUTE_PREPARATION_COST + REFUND_BASE_COST; // Masks used for setting order disabled // Different bits represent different order types uint8 private constant DEPOSIT_MASK = uint8(1) << uint8(OrderType.Deposit); // 00000010 uint8 private constant WITHDRAW_MASK = uint8(1) << uint8(OrderType.Withdraw); // 00000100 uint8 private constant SELL_MASK = uint8(1) << uint8(OrderType.Sell); // 00001000 uint8 private constant BUY_MASK = uint8(1) << uint8(OrderType.Buy); // 00010000 struct PairInfo { address pair; address token0; address token1; } struct Data { uint32 delay; uint256 newestOrderId; uint256 lastProcessedOrderId; mapping(uint256 => StoredOrder) orderQueue; address factory; uint256 maxGasLimit; uint256 gasPrice; uint256 gasPriceInertia; uint256 maxGasPriceImpact; mapping(uint32 => PairInfo) pairs; mapping(address => uint256) transferGasCosts; mapping(uint256 => bool) canceled; // Bit on specific positions indicates whether order type is disabled (1) or enabled (0) on specific pair mapping(address => uint8) orderDisabled; } struct StoredOrder { // slot 0 uint8 orderType; uint32 validAfterTimestamp; uint8 unwrapAndFailure; uint32 timestamp; uint32 gasLimit; uint32 gasPrice; uint112 liquidity; // slot 1 uint112 value0; uint112 value1; uint32 pairId; // slot2 address to; uint32 minSwapPrice; uint32 maxSwapPrice; bool swap; // slot3 uint256 priceAccumulator; } struct DepositOrder { uint32 pairId; uint256 share0; uint256 share1; uint256 minSwapPrice; uint256 maxSwapPrice; bool unwrap; bool swap; address to; uint256 gasPrice; uint256 gasLimit; uint32 validAfterTimestamp; uint256 priceAccumulator; uint32 timestamp; } struct WithdrawOrder { uint32 pairId; uint256 liquidity; uint256 amount0Min; uint256 amount1Min; bool unwrap; address to; uint256 gasPrice; uint256 gasLimit; uint32 validAfterTimestamp; } struct SellOrder { uint32 pairId; bool inverse; uint256 shareIn; uint256 amountOutMin; bool unwrap; address to; uint256 gasPrice; uint256 gasLimit; uint32 validAfterTimestamp; uint256 priceAccumulator; uint32 timestamp; } struct BuyOrder { uint32 pairId; bool inverse; uint256 shareInMax; uint256 amountOut; bool unwrap; address to; uint256 gasPrice; uint256 gasLimit; uint32 validAfterTimestamp; uint256 priceAccumulator; uint32 timestamp; } function decodeType(uint256 internalType) internal pure returns (OrderType orderType) { if (internalType == DEPOSIT_TYPE) { orderType = OrderType.Deposit; } else if (internalType == WITHDRAW_TYPE) { orderType = OrderType.Withdraw; } else if (internalType == BUY_TYPE) { orderType = OrderType.Buy; } else if (internalType == BUY_INVERTED_TYPE) { orderType = OrderType.Buy; } else if (internalType == SELL_TYPE) { orderType = OrderType.Sell; } else if (internalType == SELL_INVERTED_TYPE) { orderType = OrderType.Sell; } else { orderType = OrderType.Empty; } } function getOrder(Data storage data, uint256 orderId) public view returns (OrderType orderType, uint32 validAfterTimestamp) { StoredOrder storage order = data.orderQueue[orderId]; uint8 internalType = order.orderType; validAfterTimestamp = order.validAfterTimestamp; orderType = decodeType(internalType); } function getOrderStatus(Data storage data, uint256 orderId) external view returns (OrderStatus orderStatus) { if (orderId > data.newestOrderId) { return OrderStatus.NonExistent; } if (data.canceled[orderId]) { return OrderStatus.Canceled; } if (isRefundFailed(data, orderId)) { return OrderStatus.ExecutedFailed; } (OrderType orderType, uint32 validAfterTimestamp) = getOrder(data, orderId); if (orderType == OrderType.Empty) { return OrderStatus.ExecutedSucceeded; } if (validAfterTimestamp >= block.timestamp) { return OrderStatus.EnqueuedWaiting; } return OrderStatus.EnqueuedReady; } function getPair( Data storage data, address tokenA, address tokenB ) internal returns ( address pair, uint32 pairId, bool inverted ) { inverted = tokenA > tokenB; (address token0, address token1) = inverted ? (tokenB, tokenA) : (tokenA, tokenB); pair = ITwapFactory(data.factory).getPair(token0, token1); require(pair != address(0), 'OS17'); pairId = uint32(bytes4(keccak256(abi.encodePacked(pair)))); if (data.pairs[pairId].pair == address(0)) { data.pairs[pairId] = PairInfo(pair, token0, token1); } } function getPairInfo(Data storage data, uint32 pairId) external view returns ( address pair, address token0, address token1 ) { PairInfo storage info = data.pairs[pairId]; pair = info.pair; token0 = info.token0; token1 = info.token1; } function getDepositDisabled(Data storage data, address pair) public view returns (bool) { return data.orderDisabled[pair] & DEPOSIT_MASK != 0; } function getWithdrawDisabled(Data storage data, address pair) public view returns (bool) { return data.orderDisabled[pair] & WITHDRAW_MASK != 0; } function getSellDisabled(Data storage data, address pair) public view returns (bool) { return data.orderDisabled[pair] & SELL_MASK != 0; } function getBuyDisabled(Data storage data, address pair) public view returns (bool) { return data.orderDisabled[pair] & BUY_MASK != 0; } function getDepositOrder(Data storage data, uint256 index) public view returns (DepositOrder memory order) { StoredOrder memory stored = data.orderQueue[index]; require(stored.orderType == DEPOSIT_TYPE, 'OS32'); order.pairId = stored.pairId; order.share0 = stored.value0; order.share1 = stored.value1; order.minSwapPrice = float32ToUint(stored.minSwapPrice); order.maxSwapPrice = float32ToUint(stored.maxSwapPrice); order.unwrap = getUnwrap(stored.unwrapAndFailure); order.swap = stored.swap; order.to = stored.to; order.gasPrice = uint32ToGasPrice(stored.gasPrice); order.gasLimit = stored.gasLimit; order.validAfterTimestamp = stored.validAfterTimestamp; order.priceAccumulator = stored.priceAccumulator; order.timestamp = stored.timestamp; } function getWithdrawOrder(Data storage data, uint256 index) public view returns (WithdrawOrder memory order) { StoredOrder memory stored = data.orderQueue[index]; require(stored.orderType == WITHDRAW_TYPE, 'OS32'); order.pairId = stored.pairId; order.liquidity = stored.liquidity; order.amount0Min = stored.value0; order.amount1Min = stored.value1; order.unwrap = getUnwrap(stored.unwrapAndFailure); order.to = stored.to; order.gasPrice = uint32ToGasPrice(stored.gasPrice); order.gasLimit = stored.gasLimit; order.validAfterTimestamp = stored.validAfterTimestamp; } function getSellOrder(Data storage data, uint256 index) public view returns (SellOrder memory order) { StoredOrder memory stored = data.orderQueue[index]; require(stored.orderType == SELL_TYPE || stored.orderType == SELL_INVERTED_TYPE, 'OS32'); order.pairId = stored.pairId; order.inverse = stored.orderType == SELL_INVERTED_TYPE; order.shareIn = stored.value0; order.amountOutMin = stored.value1; order.unwrap = getUnwrap(stored.unwrapAndFailure); order.to = stored.to; order.gasPrice = uint32ToGasPrice(stored.gasPrice); order.gasLimit = stored.gasLimit; order.validAfterTimestamp = stored.validAfterTimestamp; order.priceAccumulator = stored.priceAccumulator; order.timestamp = stored.timestamp; } function getBuyOrder(Data storage data, uint256 index) public view returns (BuyOrder memory order) { StoredOrder memory stored = data.orderQueue[index]; require(stored.orderType == BUY_TYPE || stored.orderType == BUY_INVERTED_TYPE, 'OS32'); order.pairId = stored.pairId; order.inverse = stored.orderType == BUY_INVERTED_TYPE; order.shareInMax = stored.value0; order.amountOut = stored.value1; order.unwrap = getUnwrap(stored.unwrapAndFailure); order.to = stored.to; order.gasPrice = uint32ToGasPrice(stored.gasPrice); order.gasLimit = stored.gasLimit; order.validAfterTimestamp = stored.validAfterTimestamp; order.timestamp = stored.timestamp; order.priceAccumulator = stored.priceAccumulator; } function getFailedOrderType(Data storage data, uint256 orderId) external view returns (OrderType orderType, uint32 validAfterTimestamp) { require(isRefundFailed(data, orderId), 'OS21'); (orderType, validAfterTimestamp) = getOrder(data, orderId); } function getUnwrap(uint8 unwrapAndFailure) private pure returns (bool) { return unwrapAndFailure == UNWRAP_FAILED || unwrapAndFailure == UNWRAP_NOT_FAILED; } function getUnwrapAndFailure(bool unwrap) private pure returns (uint8) { return unwrap ? UNWRAP_NOT_FAILED : KEEP_NOT_FAILED; } function timestampToUint32(uint256 timestamp) private pure returns (uint32 timestamp32) { if (timestamp == type(uint256).max) { return type(uint32).max; } timestamp32 = timestamp.toUint32(); } function gasPriceToUint32(uint256 gasPrice) private pure returns (uint32 gasPrice32) { require((gasPrice / 1e6) * 1e6 == gasPrice, 'OS3C'); gasPrice32 = (gasPrice / 1e6).toUint32(); } function uint32ToGasPrice(uint32 gasPrice32) public pure returns (uint256 gasPrice) { gasPrice = uint256(gasPrice32) * 1e6; } function uintToFloat32(uint256 number) internal pure returns (uint32 float32) { // Number is encoded on 4 bytes. 3 bytes for mantissa and 1 for exponent. // If the number fits in the mantissa we set the exponent to zero and return. if (number < 2 << 24) { return uint32(number << 8); } // We find the exponent by counting the number of trailing zeroes. // Simultaneously we remove those zeroes from the number. uint32 exponent; for (exponent = 0; exponent < 256 - 24; exponent++) { // Last bit is one. if (number & 1 == 1) { break; } number = number >> 1; } // The number must fit in the mantissa. require(number < 2 << 24, 'OS1A'); // Set the first three bytes to the number and the fourth to the exponent. float32 = uint32(number << 8) | exponent; } function float32ToUint(uint32 float32) internal pure returns (uint256 number) { // Number is encoded on 4 bytes. 3 bytes for mantissa and 1 for exponent. // We get the exponent by extracting the last byte. uint256 exponent = float32 & 0xFF; // Sanity check. Only triggered for values not encoded with uintToFloat32. require(exponent <= 256 - 24, 'OS1B'); // We get the mantissa by extracting the first three bytes and removing the fourth. uint256 mantissa = (float32 & 0xFFFFFF00) >> 8; // We add exponent number zeroes after the mantissa. number = mantissa << exponent; } function setOrderDisabled( Data storage data, address pair, Orders.OrderType orderType, bool disabled ) external { require(orderType != Orders.OrderType.Empty, 'OS32'); uint8 currentSettings = data.orderDisabled[pair]; // zeros with 1 bit set at position specified by orderType uint8 mask = uint8(1) << uint8(orderType); // set/unset a bit accordingly to 'disabled' value if (disabled) { // OR operation to disable order // e.g. for disable DEPOSIT // currentSettings = 00010100 (BUY and WITHDRAW disabled) // mask for DEPOSIT = 00000010 // the result of OR = 00010110 currentSettings = currentSettings | mask; } else { // AND operation with a mask negation to enable order // e.g. for enable DEPOSIT // currentSettings = 00010100 (BUY and WITHDRAW disabled) // 0xff = 11111111 // mask for Deposit = 00000010 // mask negation = 11111101 // the result of AND = 00010100 currentSettings = currentSettings & (mask ^ 0xff); } require(currentSettings != data.orderDisabled[pair], 'OS01'); data.orderDisabled[pair] = currentSettings; emit OrderDisabled(pair, orderType, disabled); } function enqueueDepositOrder(Data storage data, DepositOrder memory depositOrder) internal { data.newestOrderId++; emit DepositEnqueued(data.newestOrderId, depositOrder.validAfterTimestamp, depositOrder.gasPrice); data.orderQueue[data.newestOrderId] = StoredOrder( DEPOSIT_TYPE, depositOrder.validAfterTimestamp, getUnwrapAndFailure(depositOrder.unwrap), depositOrder.timestamp, depositOrder.gasLimit.toUint32(), gasPriceToUint32(depositOrder.gasPrice), 0, // liquidity depositOrder.share0.toUint112(), depositOrder.share1.toUint112(), depositOrder.pairId, depositOrder.to, uintToFloat32(depositOrder.minSwapPrice), uintToFloat32(depositOrder.maxSwapPrice), depositOrder.swap, depositOrder.priceAccumulator ); } function enqueueWithdrawOrder(Data storage data, WithdrawOrder memory withdrawOrder) internal { data.newestOrderId++; emit WithdrawEnqueued(data.newestOrderId, withdrawOrder.validAfterTimestamp, withdrawOrder.gasPrice); data.orderQueue[data.newestOrderId] = StoredOrder( WITHDRAW_TYPE, withdrawOrder.validAfterTimestamp, getUnwrapAndFailure(withdrawOrder.unwrap), 0, // timestamp withdrawOrder.gasLimit.toUint32(), gasPriceToUint32(withdrawOrder.gasPrice), withdrawOrder.liquidity.toUint112(), withdrawOrder.amount0Min.toUint112(), withdrawOrder.amount1Min.toUint112(), withdrawOrder.pairId, withdrawOrder.to, 0, // minSwapPrice 0, // maxSwapPrice false, // swap 0 // priceAccumulator ); } function enqueueSellOrder(Data storage data, SellOrder memory sellOrder) internal { data.newestOrderId++; emit SellEnqueued(data.newestOrderId, sellOrder.validAfterTimestamp, sellOrder.gasPrice); data.orderQueue[data.newestOrderId] = StoredOrder( sellOrder.inverse ? SELL_INVERTED_TYPE : SELL_TYPE, sellOrder.validAfterTimestamp, getUnwrapAndFailure(sellOrder.unwrap), sellOrder.timestamp, sellOrder.gasLimit.toUint32(), gasPriceToUint32(sellOrder.gasPrice), 0, // liquidity sellOrder.shareIn.toUint112(), sellOrder.amountOutMin.toUint112(), sellOrder.pairId, sellOrder.to, 0, // minSwapPrice 0, // maxSwapPrice false, // swap sellOrder.priceAccumulator ); } function enqueueBuyOrder(Data storage data, BuyOrder memory buyOrder) internal { data.newestOrderId++; emit BuyEnqueued(data.newestOrderId, buyOrder.validAfterTimestamp, buyOrder.gasPrice); data.orderQueue[data.newestOrderId] = StoredOrder( buyOrder.inverse ? BUY_INVERTED_TYPE : BUY_TYPE, buyOrder.validAfterTimestamp, getUnwrapAndFailure(buyOrder.unwrap), buyOrder.timestamp, buyOrder.gasLimit.toUint32(), gasPriceToUint32(buyOrder.gasPrice), 0, // liquidity buyOrder.shareInMax.toUint112(), buyOrder.amountOut.toUint112(), buyOrder.pairId, buyOrder.to, 0, // minSwapPrice 0, // maxSwapPrice false, // swap buyOrder.priceAccumulator ); } function isRefundFailed(Data storage data, uint256 index) internal view returns (bool) { uint8 unwrapAndFailure = data.orderQueue[index].unwrapAndFailure; return unwrapAndFailure == UNWRAP_FAILED || unwrapAndFailure == KEEP_FAILED; } function markRefundFailed(Data storage data) internal { StoredOrder storage stored = data.orderQueue[data.lastProcessedOrderId]; stored.unwrapAndFailure = stored.unwrapAndFailure == UNWRAP_NOT_FAILED ? UNWRAP_FAILED : KEEP_FAILED; } function getNextOrder(Data storage data) internal view returns (OrderType orderType, uint256 validAfterTimestamp) { return getOrder(data, data.lastProcessedOrderId + 1); } function dequeueCanceledOrder(Data storage data) external { data.lastProcessedOrderId++; } function dequeueDepositOrder(Data storage data) external returns (DepositOrder memory order) { data.lastProcessedOrderId++; order = getDepositOrder(data, data.lastProcessedOrderId); } function dequeueWithdrawOrder(Data storage data) external returns (WithdrawOrder memory order) { data.lastProcessedOrderId++; order = getWithdrawOrder(data, data.lastProcessedOrderId); } function dequeueSellOrder(Data storage data) external returns (SellOrder memory order) { data.lastProcessedOrderId++; order = getSellOrder(data, data.lastProcessedOrderId); } function dequeueBuyOrder(Data storage data) external returns (BuyOrder memory order) { data.lastProcessedOrderId++; order = getBuyOrder(data, data.lastProcessedOrderId); } function forgetOrder(Data storage data, uint256 orderId) internal { delete data.orderQueue[orderId]; } function forgetLastProcessedOrder(Data storage data) internal { delete data.orderQueue[data.lastProcessedOrderId]; } struct DepositParams { address token0; address token1; uint256 amount0; uint256 amount1; uint256 minSwapPrice; uint256 maxSwapPrice; bool wrap; bool swap; address to; uint256 gasLimit; uint32 submitDeadline; } function deposit( Data storage data, DepositParams calldata depositParams, TokenShares.Data storage tokenShares ) external { uint256 token0TransferCost = data.transferGasCosts[depositParams.token0]; uint256 token1TransferCost = data.transferGasCosts[depositParams.token1]; require(token0TransferCost != 0 && token1TransferCost != 0, 'OS0F'); checkOrderParams( data, depositParams.to, depositParams.gasLimit, depositParams.submitDeadline, ORDER_BASE_COST.add(token0TransferCost).add(token1TransferCost) ); require(depositParams.amount0 != 0 || depositParams.amount1 != 0, 'OS25'); (address pairAddress, uint32 pairId, bool inverted) = getPair(data, depositParams.token0, depositParams.token1); require(!getDepositDisabled(data, pairAddress), 'OS46'); { // scope for value, avoids stack too deep errors uint256 value = msg.value; // allocate gas refund if (depositParams.wrap) { if (depositParams.token0 == tokenShares.weth) { value = value.sub(depositParams.amount0, 'OS1E'); } else if (depositParams.token1 == tokenShares.weth) { value = value.sub(depositParams.amount1, 'OS1E'); } } allocateGasRefund(data, value, depositParams.gasLimit); } uint256 shares0 = tokenShares.amountToShares(depositParams.token0, depositParams.amount0, depositParams.wrap); uint256 shares1 = tokenShares.amountToShares(depositParams.token1, depositParams.amount1, depositParams.wrap); (uint256 priceAccumulator, uint32 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo(); enqueueDepositOrder( data, DepositOrder( pairId, inverted ? shares1 : shares0, inverted ? shares0 : shares1, depositParams.minSwapPrice, depositParams.maxSwapPrice, depositParams.wrap, depositParams.swap, depositParams.to, data.gasPrice, depositParams.gasLimit, timestamp + data.delay, // validAfterTimestamp priceAccumulator, timestamp ) ); } struct WithdrawParams { address token0; address token1; uint256 liquidity; uint256 amount0Min; uint256 amount1Min; bool unwrap; address to; uint256 gasLimit; uint32 submitDeadline; } function withdraw(Data storage data, WithdrawParams calldata withdrawParams) external { (address pair, uint32 pairId, bool inverted) = getPair(data, withdrawParams.token0, withdrawParams.token1); require(!getWithdrawDisabled(data, pair), 'OS0A'); checkOrderParams( data, withdrawParams.to, withdrawParams.gasLimit, withdrawParams.submitDeadline, ORDER_BASE_COST.add(PAIR_TRANSFER_COST) ); require(withdrawParams.liquidity != 0, 'OS22'); allocateGasRefund(data, msg.value, withdrawParams.gasLimit); pair.safeTransferFrom(msg.sender, address(this), withdrawParams.liquidity); enqueueWithdrawOrder( data, WithdrawOrder( pairId, withdrawParams.liquidity, inverted ? withdrawParams.amount1Min : withdrawParams.amount0Min, inverted ? withdrawParams.amount0Min : withdrawParams.amount1Min, withdrawParams.unwrap, withdrawParams.to, data.gasPrice, withdrawParams.gasLimit, timestampToUint32(block.timestamp) + data.delay ) ); } struct SellParams { address tokenIn; address tokenOut; uint256 amountIn; uint256 amountOutMin; bool wrapUnwrap; address to; uint256 gasLimit; uint32 submitDeadline; } function sell( Data storage data, SellParams calldata sellParams, TokenShares.Data storage tokenShares ) external { uint256 tokenTransferCost = data.transferGasCosts[sellParams.tokenIn]; require(tokenTransferCost != 0, 'OS0F'); checkOrderParams( data, sellParams.to, sellParams.gasLimit, sellParams.submitDeadline, ORDER_BASE_COST.add(tokenTransferCost) ); require(sellParams.amountIn != 0, 'OS24'); (address pairAddress, uint32 pairId, bool inverted) = getPair(data, sellParams.tokenIn, sellParams.tokenOut); require(!getSellDisabled(data, pairAddress), 'OS13'); uint256 value = msg.value; // allocate gas refund if (sellParams.tokenIn == tokenShares.weth && sellParams.wrapUnwrap) { value = value.sub(sellParams.amountIn, 'OS1E'); } allocateGasRefund(data, value, sellParams.gasLimit); uint256 shares = tokenShares.amountToShares(sellParams.tokenIn, sellParams.amountIn, sellParams.wrapUnwrap); (uint256 priceAccumulator, uint32 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo(); enqueueSellOrder( data, SellOrder( pairId, inverted, shares, sellParams.amountOutMin, sellParams.wrapUnwrap, sellParams.to, data.gasPrice, sellParams.gasLimit, timestamp + data.delay, priceAccumulator, timestamp ) ); } struct BuyParams { address tokenIn; address tokenOut; uint256 amountInMax; uint256 amountOut; bool wrapUnwrap; address to; uint256 gasLimit; uint32 submitDeadline; } function buy( Data storage data, BuyParams calldata buyParams, TokenShares.Data storage tokenShares ) external { uint256 tokenTransferCost = data.transferGasCosts[buyParams.tokenIn]; require(tokenTransferCost != 0, 'OS0F'); checkOrderParams( data, buyParams.to, buyParams.gasLimit, buyParams.submitDeadline, ORDER_BASE_COST.add(tokenTransferCost) ); require(buyParams.amountOut != 0, 'OS23'); (address pairAddress, uint32 pairId, bool inverted) = getPair(data, buyParams.tokenIn, buyParams.tokenOut); require(!getBuyDisabled(data, pairAddress), 'OS49'); uint256 value = msg.value; // allocate gas refund if (buyParams.tokenIn == tokenShares.weth && buyParams.wrapUnwrap) { value = value.sub(buyParams.amountInMax, 'OS1E'); } allocateGasRefund(data, value, buyParams.gasLimit); uint256 shares = tokenShares.amountToShares(buyParams.tokenIn, buyParams.amountInMax, buyParams.wrapUnwrap); (uint256 priceAccumulator, uint32 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo(); enqueueBuyOrder( data, BuyOrder( pairId, inverted, shares, buyParams.amountOut, buyParams.wrapUnwrap, buyParams.to, data.gasPrice, buyParams.gasLimit, timestamp + data.delay, priceAccumulator, timestamp ) ); } function checkOrderParams( Data storage data, address to, uint256 gasLimit, uint32 submitDeadline, uint256 minGasLimit ) private view { require(submitDeadline >= block.timestamp, 'OS04'); require(gasLimit <= data.maxGasLimit, 'OS3E'); require(gasLimit >= minGasLimit, 'OS3D'); require(to != address(0), 'OS26'); } function allocateGasRefund( Data storage data, uint256 value, uint256 gasLimit ) private returns (uint256 futureFee) { futureFee = data.gasPrice.mul(gasLimit); require(value >= futureFee, 'OS1E'); if (value > futureFee) { TransferHelper.safeTransferETH(msg.sender, value.sub(futureFee), data.transferGasCosts[address(0)]); } } function updateGasPrice(Data storage data, uint256 gasUsed) external { uint256 scale = Math.min(gasUsed, data.maxGasPriceImpact); uint256 updated = data.gasPrice.mul(data.gasPriceInertia.sub(scale)).add(tx.gasprice.mul(scale)).div( data.gasPriceInertia ); // we lower the precision for gas savings in order queue data.gasPrice = updated - (updated % 1e6); } function setMaxGasLimit(Data storage data, uint256 _maxGasLimit) external { require(_maxGasLimit != data.maxGasLimit, 'OS01'); require(_maxGasLimit <= 10000000, 'OS2B'); data.maxGasLimit = _maxGasLimit; emit MaxGasLimitSet(_maxGasLimit); } function setGasPriceInertia(Data storage data, uint256 _gasPriceInertia) external { require(_gasPriceInertia != data.gasPriceInertia, 'OS01'); require(_gasPriceInertia >= 1, 'OS35'); data.gasPriceInertia = _gasPriceInertia; emit GasPriceInertiaSet(_gasPriceInertia); } function setMaxGasPriceImpact(Data storage data, uint256 _maxGasPriceImpact) external { require(_maxGasPriceImpact != data.maxGasPriceImpact, 'OS01'); require(_maxGasPriceImpact <= data.gasPriceInertia, 'OS33'); data.maxGasPriceImpact = _maxGasPriceImpact; emit MaxGasPriceImpactSet(_maxGasPriceImpact); } function setTransferGasCost( Data storage data, address token, uint256 gasCost ) external { require(gasCost != data.transferGasCosts[token], 'OS01'); data.transferGasCosts[token] = gasCost; emit TransferGasCostSet(token, gasCost); } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; import '../interfaces/IERC20.sol'; import '../interfaces/IWETH.sol'; import './SafeMath.sol'; import './TransferHelper.sol'; library TokenShares { using SafeMath for uint256; using TransferHelper for address; event UnwrapFailed(address to, uint256 amount); struct Data { mapping(address => uint256) totalShares; address weth; } function setWeth(Data storage data, address _weth) internal { data.weth = _weth; } function sharesToAmount( Data storage data, address token, uint256 share ) external returns (uint256) { if (share == 0) { return 0; } if (token == data.weth) { return share; } uint256 totalTokenShares = data.totalShares[token]; require(totalTokenShares >= share, 'TS3A'); uint256 balance = IERC20(token).balanceOf(address(this)); uint256 value = balance.mul(share).div(totalTokenShares); data.totalShares[token] = totalTokenShares.sub(share); return value; } function amountToShares( Data storage data, address token, uint256 amount, bool wrap ) external returns (uint256) { if (amount == 0) { return 0; } if (token == data.weth) { if (wrap) { require(msg.value >= amount, 'TS03'); IWETH(token).deposit{ value: amount }(); } else { token.safeTransferFrom(msg.sender, address(this), amount); } return amount; } else { uint256 balanceBefore = IERC20(token).balanceOf(address(this)); uint256 totalTokenShares = data.totalShares[token]; require(balanceBefore > 0 || totalTokenShares == 0, 'TS30'); if (totalTokenShares == 0) { totalTokenShares = balanceBefore; } token.safeTransferFrom(msg.sender, address(this), amount); uint256 balanceAfter = IERC20(token).balanceOf(address(this)); require(balanceAfter > balanceBefore, 'TS2C'); if (balanceBefore > 0) { uint256 newShares = totalTokenShares.mul(balanceAfter).div(balanceBefore); data.totalShares[token] = newShares; return newShares - totalTokenShares; } else { data.totalShares[token] = balanceAfter; return balanceAfter; } } } function onUnwrapFailed( Data storage data, address to, uint256 amount ) external { emit UnwrapFailed(to, amount); IWETH(data.weth).deposit{ value: amount }(); TransferHelper.safeTransfer(data.weth, to, amount); } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; import './TransferHelper.sol'; import './SafeMath.sol'; import './Math.sol'; import '../interfaces/ITwapPair.sol'; import '../interfaces/ITwapOracle.sol'; library AddLiquidity { using SafeMath for uint256; function _quote( uint256 amount0, uint256 reserve0, uint256 reserve1 ) private pure returns (uint256 amountB) { require(amount0 > 0, 'AL03'); require(reserve0 > 0 && reserve1 > 0, 'AL07'); amountB = amount0.mul(reserve1) / reserve0; } function addLiquidity( address pair, uint256 amount0Desired, uint256 amount1Desired ) internal view returns (uint256 amount0, uint256 amount1) { if (amount0Desired == 0 || amount1Desired == 0) { return (0, 0); } (uint256 reserve0, uint256 reserve1) = ITwapPair(pair).getReserves(); if (reserve0 == 0 && reserve1 == 0) { (amount0, amount1) = (amount0Desired, amount1Desired); } else { uint256 amount1Optimal = _quote(amount0Desired, reserve0, reserve1); if (amount1Optimal <= amount1Desired) { (amount0, amount1) = (amount0Desired, amount1Optimal); } else { uint256 amount0Optimal = _quote(amount1Desired, reserve1, reserve0); assert(amount0Optimal <= amount0Desired); (amount0, amount1) = (amount0Optimal, amount1Desired); } } } function addLiquidityAndMint( address pair, address to, address token0, address token1, uint256 amount0Desired, uint256 amount1Desired ) external returns (uint256 amount0Left, uint256 amount1Left) { (uint256 amount0, uint256 amount1) = addLiquidity(pair, amount0Desired, amount1Desired); if (amount0 == 0 || amount1 == 0) { return (amount0Desired, amount1Desired); } TransferHelper.safeTransfer(token0, pair, amount0); TransferHelper.safeTransfer(token1, pair, amount1); ITwapPair(pair).mint(to); amount0Left = amount0Desired.sub(amount0); amount1Left = amount1Desired.sub(amount1); } function swapDeposit0( address pair, address token0, uint256 amount0, uint256 minSwapPrice, bytes calldata data ) external returns (uint256 amount0Left, uint256 amount1Left) { uint256 amount0In = ITwapPair(pair).getDepositAmount0In(amount0, data); amount1Left = ITwapPair(pair).getSwapAmount1Out(amount0In, data); if (amount1Left == 0) { return (amount0, amount1Left); } uint256 price = getPrice(amount0In, amount1Left, pair); require(minSwapPrice == 0 || price >= minSwapPrice, 'AL15'); TransferHelper.safeTransfer(token0, pair, amount0In); ITwapPair(pair).swap(0, amount1Left, address(this), data); amount0Left = amount0.sub(amount0In); } function swapDeposit1( address pair, address token1, uint256 amount1, uint256 maxSwapPrice, bytes calldata data ) external returns (uint256 amount0Left, uint256 amount1Left) { uint256 amount1In = ITwapPair(pair).getDepositAmount1In(amount1, data); amount0Left = ITwapPair(pair).getSwapAmount0Out(amount1In, data); if (amount0Left == 0) { return (amount0Left, amount1); } uint256 price = getPrice(amount0Left, amount1In, pair); require(maxSwapPrice == 0 || price <= maxSwapPrice, 'AL16'); TransferHelper.safeTransfer(token1, pair, amount1In); ITwapPair(pair).swap(amount0Left, 0, address(this), data); amount1Left = amount1.sub(amount1In); } function getPrice( uint256 amount0, uint256 amount1, address pair ) internal view returns (uint256) { ITwapOracle oracle = ITwapOracle(ITwapPair(pair).oracle()); return amount1.mul(uint256(oracle.decimalsConverter())).div(amount0); } }
// 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; 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; // 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 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; // 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 }(''); } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; import './interfaces/ITwapPair.sol'; import './libraries/Reserves.sol'; import './TwapLPToken.sol'; import './libraries/Math.sol'; import './interfaces/IERC20.sol'; import './interfaces/ITwapFactory.sol'; import './interfaces/ITwapOracle.sol'; contract TwapPair is Reserves, TwapLPToken, ITwapPair { using SafeMath for uint256; uint256 private constant PRECISION = 10**18; uint256 public override mintFee = 0; uint256 public override burnFee = 0; uint256 public override swapFee = 0; uint256 public constant override MINIMUM_LIQUIDITY = 10**3; bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)'))); address public immutable override factory; address public override token0; address public override token1; address public override oracle; address public override trader; uint256 private unlocked = 1; modifier lock() { require(unlocked == 1, 'TP06'); unlocked = 0; _; unlocked = 1; } function isContract(address addr) private view returns (bool) { uint256 size; assembly { size := extcodesize(addr) } return size > 0; } function setMintFee(uint256 fee) external override { require(msg.sender == factory, 'TP00'); require(fee != mintFee, 'TP01'); mintFee = fee; emit SetMintFee(fee); } function setBurnFee(uint256 fee) external override { require(msg.sender == factory, 'TP00'); require(fee != burnFee, 'TP01'); burnFee = fee; emit SetBurnFee(fee); } function setSwapFee(uint256 fee) external override { require(msg.sender == factory, 'TP00'); require(fee != swapFee, 'TP01'); swapFee = fee; emit SetSwapFee(fee); } function setOracle(address _oracle) external override { require(msg.sender == factory, 'TP00'); require(_oracle != oracle, 'TP01'); require(_oracle != address(0), 'TP02'); require(isContract(_oracle), 'TP1D'); oracle = _oracle; emit SetOracle(_oracle); } function setTrader(address _trader) external override { require(msg.sender == factory, 'TP00'); require(_trader != trader, 'TP01'); // Allow trader to be set as address(0) to disable interaction trader = _trader; emit SetTrader(_trader); } function collect(address to) external override lock { require(msg.sender == factory, 'TP00'); require(to != address(0), 'TP02'); (uint256 fee0, uint256 fee1) = getFees(); if (fee0 > 0) _safeTransfer(token0, to, fee0); if (fee1 > 0) _safeTransfer(token1, to, fee1); setFees(0, 0); _sync(); } function _safeTransfer( address token, address to, uint256 value ) private { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TP05'); } function canTrade(address user) private view returns (bool) { return user == trader || user == factory; } constructor() { factory = msg.sender; } // called once by the factory at time of deployment function initialize( address _token0, address _token1, address _oracle, address _trader ) external override { require(msg.sender == factory, 'TP00'); require(_oracle != address(0), 'TP02'); require(isContract(_oracle), 'TP1D'); require(isContract(_token0) && isContract(_token1), 'TP10'); token0 = _token0; token1 = _token1; oracle = _oracle; trader = _trader; } // this low-level function should be called from a contract which performs important safety checks function mint(address to) external override lock returns (uint256 liquidityOut) { require(canTrade(msg.sender), 'TP0C'); require(to != address(0), 'TP02'); (uint112 reserve0, uint112 reserve1) = getReserves(); (uint256 balance0, uint256 balance1) = getBalances(token0, token1); uint256 amount0In = balance0.sub(reserve0); uint256 amount1In = balance1.sub(reserve1); uint256 _totalSupply = totalSupply; // gas savings if (_totalSupply == 0) { liquidityOut = Math.sqrt(amount0In.mul(amount1In)).sub(MINIMUM_LIQUIDITY); _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens } else { liquidityOut = Math.min(amount0In.mul(_totalSupply) / reserve0, amount1In.mul(_totalSupply) / reserve1); } require(liquidityOut > 0, 'TP38'); if (mintFee > 0) { uint256 fee = liquidityOut.mul(mintFee).div(PRECISION); liquidityOut = liquidityOut.sub(fee); _mint(factory, fee); } _mint(to, liquidityOut); setReserves(balance0, balance1); emit Mint(msg.sender, amount0In, amount1In, liquidityOut, to); } // this low-level function should be called from a contract which performs important safety checks function burn(address to) external override lock returns (uint256 amount0Out, uint256 amount1Out) { require(canTrade(msg.sender), 'TP0C'); require(to != address(0), 'TP02'); uint256 _totalSupply = totalSupply; // gas savings require(_totalSupply > 0, 'TP36'); address _token0 = token0; // gas savings address _token1 = token1; // gas savings (uint256 balance0, uint256 balance1) = getBalances(token0, token1); uint256 liquidityIn = balanceOf[address(this)]; if (msg.sender != factory && burnFee > 0) { uint256 fee = liquidityIn.mul(burnFee).div(PRECISION); liquidityIn = liquidityIn.sub(fee); _transfer(address(this), factory, fee); } _burn(address(this), liquidityIn); amount0Out = liquidityIn.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution amount1Out = liquidityIn.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution require(amount0Out > 0 && amount1Out > 0, 'TP39'); _safeTransfer(_token0, to, amount0Out); _safeTransfer(_token1, to, amount1Out); (balance0, balance1) = getBalances(token0, token1); setReserves(balance0, balance1); emit Burn(msg.sender, amount0Out, amount1Out, liquidityIn, to); } // this low-level function should be called from a contract which performs important safety checks function swap( uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data ) external override lock { require(canTrade(msg.sender), 'TP0C'); require(to != address(0), 'TP02'); require((amount0Out > 0 && amount1Out == 0) || (amount1Out > 0 && amount0Out == 0), 'TP31'); (uint112 _reserve0, uint112 _reserve1) = getReserves(); require(amount0Out < _reserve0 && amount1Out < _reserve1, 'TP07'); { // scope for _token{0,1}, avoids stack too deep errors address _token0 = token0; address _token1 = token1; require(to != _token0 && to != _token1, 'TP2D'); if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens } (uint256 balance0, uint256 balance1) = getBalances(token0, token1); if (amount0Out > 0) { // trading token1 for token0 require(balance1 > _reserve1, 'TP08'); uint256 amount1In = balance1 - _reserve1; emit Swap(msg.sender, 0, amount1In, amount0Out, 0, to); uint256 fee1 = amount1In.mul(swapFee).div(PRECISION); uint256 balance1After = balance1.sub(fee1); uint256 balance0After = ITwapOracle(oracle).tradeY(balance1After, _reserve0, _reserve1, data); require(balance0 >= balance0After, 'TP2E'); uint256 fee0 = balance0.sub(balance0After); addFees(fee0, fee1); setReserves(balance0After, balance1After); } else { // trading token0 for token1 require(balance0 > _reserve0, 'TP08'); uint256 amount0In = balance0 - _reserve0; emit Swap(msg.sender, amount0In, 0, 0, amount1Out, to); uint256 fee0 = amount0In.mul(swapFee).div(PRECISION); uint256 balance0After = balance0.sub(fee0); uint256 balance1After = ITwapOracle(oracle).tradeX(balance0After, _reserve0, _reserve1, data); require(balance1 >= balance1After, 'TP2E'); uint256 fee1 = balance1.sub(balance1After); addFees(fee0, fee1); setReserves(balance0After, balance1After); } } function sync() external override lock { require(canTrade(msg.sender), 'TP0C'); _sync(); } // force reserves to match balances function _sync() internal { syncReserves(token0, token1); uint256 tokens = balanceOf[address(this)]; if (tokens > 0) { _transfer(address(this), factory, tokens); } } function getSwapAmount0In(uint256 amount1Out, bytes calldata data) public view override returns (uint256 swapAmount0In) { (uint112 reserve0, uint112 reserve1) = getReserves(); uint256 balance1After = uint256(reserve1).sub(amount1Out); uint256 balance0After = ITwapOracle(oracle).tradeY(balance1After, reserve0, reserve1, data); return balance0After.sub(uint256(reserve0)).mul(PRECISION).ceil_div(PRECISION.sub(swapFee)); } function getSwapAmount1In(uint256 amount0Out, bytes calldata data) public view override returns (uint256 swapAmount1In) { (uint112 reserve0, uint112 reserve1) = getReserves(); uint256 balance0After = uint256(reserve0).sub(amount0Out); uint256 balance1After = ITwapOracle(oracle).tradeX(balance0After, reserve0, reserve1, data); return balance1After.add(1).sub(uint256(reserve1)).mul(PRECISION).ceil_div(PRECISION.sub(swapFee)); } function getSwapAmount0Out(uint256 amount1In, bytes calldata data) public view override returns (uint256 swapAmount0Out) { (uint112 reserve0, uint112 reserve1) = getReserves(); uint256 fee = amount1In.mul(swapFee).div(PRECISION); uint256 balance0After = ITwapOracle(oracle).tradeY( uint256(reserve1).add(amount1In).sub(fee), reserve0, reserve1, data ); return uint256(reserve0).sub(balance0After); } function getSwapAmount1Out(uint256 amount0In, bytes calldata data) public view override returns (uint256 swapAmount1Out) { (uint112 reserve0, uint112 reserve1) = getReserves(); uint256 fee = amount0In.mul(swapFee).div(PRECISION); uint256 balance1After = ITwapOracle(oracle).tradeX( uint256(reserve0).add(amount0In).sub(fee), reserve0, reserve1, data ); return uint256(reserve1).sub(balance1After); } function getDepositAmount0In(uint256 amount0, bytes calldata data) external view override returns (uint256) { (uint112 reserve0, uint112 reserve1) = getReserves(); return ITwapOracle(oracle).depositTradeXIn(amount0, reserve0, reserve1, data); } function getDepositAmount1In(uint256 amount1, bytes calldata data) external view override returns (uint256) { (uint112 reserve0, uint112 reserve1) = getReserves(); return ITwapOracle(oracle).depositTradeYIn(amount1, reserve0, reserve1, data); } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; import '../interfaces/IReserves.sol'; import '../interfaces/IERC20.sol'; import '../libraries/SafeMath.sol'; contract Reserves is IReserves { using SafeMath for uint256; uint112 private reserve0; uint112 private reserve1; uint112 private fee0; uint112 private fee1; function getReserves() public view override returns (uint112, uint112) { return (reserve0, reserve1); } function setReserves(uint256 balance0MinusFee, uint256 balance1MinusFee) internal { require(balance0MinusFee != 0 && balance1MinusFee != 0, 'RS09'); reserve0 = balance0MinusFee.toUint112(); reserve1 = balance1MinusFee.toUint112(); } function syncReserves(address token0, address token1) internal { uint256 balance0 = IERC20(token0).balanceOf(address(this)); uint256 balance1 = IERC20(token1).balanceOf(address(this)); uint256 oldBalance0 = uint256(reserve0) + fee0; uint256 oldBalance1 = uint256(reserve1) + fee1; if (balance0 != oldBalance0 || balance1 != oldBalance1) { if (oldBalance0 != 0) { fee0 = (balance0.mul(fee0).div(oldBalance0)).toUint112(); } if (oldBalance1 != 0) { fee1 = (balance1.mul(fee1).div(oldBalance1)).toUint112(); } setReserves(balance0.sub(fee0), balance1.sub(fee1)); } } function getFees() public view override returns (uint256, uint256) { return (fee0, fee1); } function addFees(uint256 _fee0, uint256 _fee1) internal { setFees(_fee0.add(fee0), _fee1.add(fee1)); } function setFees(uint256 _fee0, uint256 _fee1) internal { fee0 = _fee0.toUint112(); fee1 = _fee1.toUint112(); } function getBalances(address token0, address token1) internal returns (uint256, uint256) { uint256 balance0 = IERC20(token0).balanceOf(address(this)); uint256 balance1 = IERC20(token1).balanceOf(address(this)); if (fee0 > balance0) { fee0 = uint112(balance0); } if (fee1 > balance1) { fee1 = uint112(balance1); } return (balance0.sub(fee0), balance1.sub(fee1)); } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; import './libraries/AbstractERC20.sol'; contract TwapLPToken is AbstractERC20 { constructor() { name = 'Twap LP'; symbol = 'TWAP-LP'; decimals = 18; } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; import '../interfaces/ITwapERC20.sol'; import './SafeMath.sol'; abstract contract AbstractERC20 is ITwapERC20 { using SafeMath for uint256; string public override name; string public override symbol; uint8 public override decimals; uint256 public override totalSupply; mapping(address => uint256) public override balanceOf; mapping(address => mapping(address => uint256)) public override allowance; bytes32 public constant DOMAIN_TYPEHASH = keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'); // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); bytes32 public constant override PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; mapping(address => uint256) public override nonces; function _mint(address to, uint256 value) internal { totalSupply = totalSupply.add(value); balanceOf[to] = balanceOf[to].add(value); emit Transfer(address(0), to, value); } function _burn(address from, uint256 value) internal { balanceOf[from] = balanceOf[from].sub(value); totalSupply = totalSupply.sub(value); emit Transfer(from, address(0), value); } function _approve( address owner, address spender, uint256 value ) internal { allowance[owner][spender] = value; emit Approval(owner, spender, value); } function _transfer( address from, address to, uint256 value ) internal { balanceOf[from] = balanceOf[from].sub(value); balanceOf[to] = balanceOf[to].add(value); emit Transfer(from, to, value); } function approve(address spender, uint256 value) external override returns (bool) { _approve(msg.sender, spender, value); return true; } function increaseAllowance(address spender, uint256 addedValue) external override returns (bool) { _approve(msg.sender, spender, allowance[msg.sender][spender].add(addedValue)); return true; } function decreaseAllowance(address spender, uint256 subtractedValue) external override returns (bool) { uint256 currentAllowance = allowance[msg.sender][spender]; require(currentAllowance >= subtractedValue, 'TA48'); _approve(msg.sender, spender, currentAllowance.sub(subtractedValue)); return true; } function transfer(address to, uint256 value) external override returns (bool) { _transfer(msg.sender, to, value); return true; } function transferFrom( address from, address to, uint256 value ) external override returns (bool) { if (allowance[from][msg.sender] != uint256(-1)) { allowance[from][msg.sender] = allowance[from][msg.sender].sub(value); } _transfer(from, to, value); return true; } function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external override { require(deadline >= block.timestamp, 'TA04'); bytes32 digest = keccak256( abi.encodePacked( '\x19\x01', getDomainSeparator(), keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) ) ); address recoveredAddress = ecrecover(digest, v, r, s); require(recoveredAddress != address(0) && recoveredAddress == owner, 'TA2F'); _approve(owner, spender, value); } function getDomainSeparator() public view returns (bytes32) { uint256 chainId; assembly { chainId := chainid() } return keccak256( abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), keccak256(bytes('1')), chainId, address(this)) ); } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; import './interfaces/ITwapFactory.sol'; import './TwapPair.sol'; contract TwapFactory is ITwapFactory { mapping(address => mapping(address => address)) public override getPair; address[] public override allPairs; address public override owner; constructor() { owner = msg.sender; emit OwnerSet(msg.sender); } function allPairsLength() external view override returns (uint256) { return allPairs.length; } function createPair( address tokenA, address tokenB, address oracle, address trader ) external override returns (address pair) { require(msg.sender == owner, 'TF00'); require(tokenA != tokenB, 'TF3B'); (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), 'TF02'); require(getPair[token0][token1] == address(0), 'TF18'); // single check is sufficient bytes memory bytecode = type(TwapPair).creationCode; bytes32 salt = keccak256(abi.encodePacked(token0, token1)); assembly { pair := create2(0, add(bytecode, 32), mload(bytecode), salt) } ITwapPair(pair).initialize(token0, token1, oracle, trader); getPair[token0][token1] = pair; getPair[token1][token0] = pair; // populate mapping in the reverse direction allPairs.push(pair); emit PairCreated(token0, token1, pair, allPairs.length); } function setOwner(address _owner) external override { require(msg.sender == owner, 'TF00'); require(_owner != owner, 'TF01'); require(_owner != address(0), 'TF02'); owner = _owner; emit OwnerSet(_owner); } function setMintFee( address tokenA, address tokenB, uint256 fee ) external override { require(msg.sender == owner, 'TF00'); _getPair(tokenA, tokenB).setMintFee(fee); } function setBurnFee( address tokenA, address tokenB, uint256 fee ) external override { require(msg.sender == owner, 'TF00'); _getPair(tokenA, tokenB).setBurnFee(fee); } function setSwapFee( address tokenA, address tokenB, uint256 fee ) external override { require(msg.sender == owner, 'TF00'); _getPair(tokenA, tokenB).setSwapFee(fee); } function setOracle( address tokenA, address tokenB, address oracle ) external override { require(msg.sender == owner, 'TF00'); _getPair(tokenA, tokenB).setOracle(oracle); } function setTrader( address tokenA, address tokenB, address trader ) external override { require(msg.sender == owner, 'TF00'); _getPair(tokenA, tokenB).setTrader(trader); } function collect( address tokenA, address tokenB, address to ) external override { require(msg.sender == owner, 'TF00'); _getPair(tokenA, tokenB).collect(to); } function withdraw( address tokenA, address tokenB, uint256 amount, address to ) external override { require(msg.sender == owner, 'TF00'); ITwapPair pair = _getPair(tokenA, tokenB); pair.transfer(address(pair), amount); pair.burn(to); } function _getPair(address tokenA, address tokenB) internal view returns (ITwapPair pair) { pair = ITwapPair(getPair[tokenA][tokenB]); require(address(pair) != address(0), 'TF19'); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": { "contracts/libraries/AddLiquidity.sol": { "AddLiquidity": "0xb291730099d3ac9975abd4003ba3bd47401fd2fd" }, "contracts/libraries/Orders.sol": { "Orders": "0x6336788a85f54d8856782d58c1ca63c7d3844531" }, "contracts/libraries/TokenShares.sol": { "TokenShares": "0xb28c804e3dacff80701bbbafd106dbfb416a5168" }, "contracts/libraries/WithdrawHelper.sol": { "WithdrawHelper": "0x6195015b38773f468dd43620dd5a64e9bb63c2e3" } } }
Contract Security Audit
- 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":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"gasCost","type":"uint256"}],"name":"TransferGasCostSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"UnwrapFailed","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"bool","name":"inverse","type":"bool"},{"internalType":"uint256","name":"shareInMax","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.BuyOrder","name":"buyOrder","type":"tuple"}],"name":"_executeBuy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"uint256","name":"share0","type":"uint256"},{"internalType":"uint256","name":"share1","type":"uint256"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.DepositOrder","name":"depositOrder","type":"tuple"}],"name":"_executeDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"bool","name":"inverse","type":"bool"},{"internalType":"uint256","name":"shareIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.SellOrder","name":"sellOrder","type":"tuple"}],"name":"_executeSell","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"}],"internalType":"struct Orders.WithdrawOrder","name":"withdrawOrder","type":"tuple"}],"name":"_executeWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"name":"_refundLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"share","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"}],"name":"_refundToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"uint256","name":"share0","type":"uint256"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"share1","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"}],"name":"_refundTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"bool","name":"wrapUnwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.BuyParams","name":"buyParams","type":"tuple"}],"name":"buy","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delay","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"wrap","type":"bool"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.DepositParams","name":"depositParams","type":"tuple"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"n","type":"uint256"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasPriceInertia","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getBuyDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getBuyOrder","outputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"bool","name":"inverse","type":"bool"},{"internalType":"uint256","name":"shareInMax","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.BuyOrder","name":"order","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getDepositDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getDepositOrder","outputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"uint256","name":"share0","type":"uint256"},{"internalType":"uint256","name":"share1","type":"uint256"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.DepositOrder","name":"order","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getOrder","outputs":[{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getOrderStatus","outputs":[{"internalType":"enum Orders.OrderStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getSellDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getSellOrder","outputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"bool","name":"inverse","type":"bool"},{"internalType":"uint256","name":"shareIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"internalType":"struct Orders.SellOrder","name":"order","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTransferGasCost","outputs":[{"internalType":"uint256","name":"gasCost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getWithdrawDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"getWithdrawOrder","outputs":[{"components":[{"internalType":"uint32","name":"pairId","type":"uint32"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"validAfterTimestamp","type":"uint32"}],"internalType":"struct Orders.WithdrawOrder","name":"order","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isBot","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"isOrderCanceled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastProcessedOrderId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxGasLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxGasPriceImpact","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newestOrderId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"retryRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"wrapUnwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.SellParams","name":"sellParams","type":"tuple"}],"name":"sell","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_bot","type":"address"},{"internalType":"bool","name":"_isBot","type":"bool"}],"name":"setBot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_delay","type":"uint32"}],"name":"setDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasPriceInertia","type":"uint256"}],"name":"setGasPriceInertia","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxGasLimit","type":"uint256"}],"name":"setMaxGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxGasPriceImpact","type":"uint256"}],"name":"setMaxGasPriceImpact","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"disabled","type":"bool"}],"name":"setOrderDisabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"gasCost","type":"uint256"}],"name":"setTransferGasCost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.WithdrawParams","name":"withdrawParams","type":"tuple"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405260016011553480156200001657600080fd5b5060405162005fc938038062005fc98339810160408190526200003991620001bd565b600480546001600160a01b038086166001600160a01b031992831617909255600f80549091163317905581166000908152601060205260409020805460ff19166001179055620f42403a063a03600655620000a2600d836200017b602090811b6200296d17901c565b6000805463ffffffff1916610708178155624c4b406005556301312d00600755620f424060085560405163b2456a0760e01b8152736336788a85f54d8856782d58c1ca63c7d38445319163b2456a07916200010791908190612710906004016200021a565b60006040518083038186803b1580156200012057600080fd5b505af415801562000135573d6000803e3d6000fd5b505050507f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe2336040516200016a919062000206565b60405180910390a150505062000239565b60019190910180546001600160a01b0319166001600160a01b03909216919091179055565b80516001600160a01b0381168114620001b857600080fd5b919050565b600080600060608486031215620001d2578283fd5b620001dd84620001a0565b9250620001ed60208501620001a0565b9150620001fd60408501620001a0565b90509250925092565b6001600160a01b0391909116815260200190565b9283526001600160a01b03919091166020830152604082015260600190565b615d8080620002496000396000f3fe6080604052600436106102815760003560e01c806377632ec21161014f578063be581304116100c1578063e30a49931161007a578063e30a49931461078d578063e5b1be65146107a2578063e5e7988e146107c2578063e6a0cc94146107e2578063fe0d94c1146107f7578063fe173b971461081757610288565b8063be581304146106ca578063bf6b874e146106ea578063c45a01551461070a578063c9cd97601461071f578063d09ef2411461073f578063d22e92421461076d57610288565b80639d08ebb5116101135780639d08ebb5146106245780639da92cfa14610637578063af482b5814610657578063b1af1bda14610677578063b32ac93614610697578063ba4d5312146106b757610288565b806377632ec21461058f5780637f6a1caf146105af5780638da5cb5b146105cf57806394531713146105e45780639718f6271461060457610288565b80633fc8cef3116101f3578063576b332b116101ac578063576b332b146104fb57806357a62a4f1461050e5780635e45da2314610523578063690910c4146105385780636a42b8f8146105585780636de3c67c1461057a57610288565b80633fc8cef31461041f57806345fa8aae146104415780634c0160161461046e5780635051349a1461048e578063514fcac7146104ae57806354df6d74146104ce57610288565b806320a68fab1161024557806320a68fab14610345578063342aa8b514610372578063390ce0d3146103925780633bbac579146103bf5780633c763c17146103df5780633ed76f17146103ff57610288565b80630b65604d1461028d57806310348665146102af57806313af4035146102cf5780631776834a146102ef57806317818a5c1461030f57610288565b3661028857005b600080fd5b34801561029957600080fd5b506102ad6102a8366004614ff5565b61082c565b005b3480156102bb57600080fd5b506102ad6102ca36600461536b565b610c10565b3480156102db57600080fd5b506102ad6102ea366004614d27565b610cb5565b3480156102fb57600080fd5b506102ad61030a366004615318565b610d7e565b34801561031b57600080fd5b5061032f61032a366004615318565b610e15565b60405161033c9190615ba0565b60405180910390f35b34801561035157600080fd5b50610365610360366004614d27565b610eb0565b60405161033c9190615692565b34801561037e57600080fd5b506102ad61038d366004614eac565b610f3c565b34801561039e57600080fd5b506103b26103ad366004615318565b611007565b60405161033c919061587d565b3480156103cb57600080fd5b506103656103da366004614d27565b61109a565b3480156103eb57600080fd5b506102ad6103fa366004614ff5565b6110af565b34801561040b57600080fd5b506102ad61041a366004614deb565b611482565b34801561042b57600080fd5b506104346114a2565b60405161033c919061552d565b34801561044d57600080fd5b5061046161045c366004615318565b6114b1565b60405161033c91906156c2565b34801561047a57600080fd5b50610365610489366004614d27565b61153d565b6104a161049c36600461502d565b611579565b60405161033c91906158ab565b3480156104ba57600080fd5b506102ad6104c9366004615318565b61161d565b3480156104da57600080fd5b506104ee6104e9366004615318565b611807565b60405161033c9190615ada565b6104a1610509366004615306565b61189a565b34801561051a57600080fd5b506104a16118fd565b34801561052f57600080fd5b506104a1611903565b34801561054457600080fd5b506102ad6105533660046151f0565b611909565b34801561056457600080fd5b5061056d611c97565b60405161033c9190615c67565b34801561058657600080fd5b506104a1611ca3565b34801561059b57600080fd5b506103656105aa366004615318565b611ca9565b3480156105bb57600080fd5b506102ad6105ca366004614ee4565b611cbe565b3480156105db57600080fd5b50610434611d52565b3480156105f057600080fd5b506102ad6105ff366004615318565b611d61565b34801561061057600080fd5b506104a161061f366004614d27565b611dc5565b6104a16106323660046151de565b611de0565b34801561064357600080fd5b506102ad610652366004615049565b611e46565b34801561066357600080fd5b50610365610672366004614d27565b6120df565b34801561068357600080fd5b506103b2610692366004615318565b61211b565b3480156106a357600080fd5b506102ad6106b2366004615318565b61215d565b6104a16106c536600461502d565b6121c1565b3480156106d657600080fd5b506102ad6106e5366004615318565b612227565b3480156106f657600080fd5b506104a1610705366004614d27565b6122f1565b34801561071657600080fd5b5061043461230c565b34801561072b57600080fd5b506102ad61073a366004614dab565b61231b565b34801561074b57600080fd5b5061075f61075a366004615318565b61234a565b60405161033c9291906156d6565b34801561077957600080fd5b506102ad610788366004614f23565b6123e0565b34801561079957600080fd5b506104a1612472565b3480156107ae57600080fd5b506102ad6107bd366004614e5a565b612478565b3480156107ce57600080fd5b506103656107dd366004614d27565b61266e565b3480156107ee57600080fd5b506104a16126aa565b34801561080357600080fd5b506102ad610812366004615318565b6126b0565b34801561082357600080fd5b506104a1612967565b3330146108545760405162461bcd60e51b815260040161084b9061578d565b60405180910390fd5b426202a30082610100015163ffffffff160110156108845760405162461bcd60e51b815260040161084b906157e7565b600080600061089b84600001518560200151612992565b9250925092506000600d73b28c804e3dacff80701bbbafd106dbfb416a5168636c5d9cf090918588604001516040518463ffffffff1660e01b81526004016108e59392919061588c565b60206040518083038186803b1580156108fd57600080fd5b505af4158015610911573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109359190615330565b90506000849050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561097757600080fd5b505af115801561098b573d6000803e3d6000fd5b5050505060006109a686886101200151896101400151612a52565b905060008760200151610a3657604051632b9b015d60e01b81526001600160a01b03841690632b9b015d906109e19087908690600401615c17565b60206040518083038186803b1580156109f957600080fd5b505afa158015610a0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a319190615330565b610ab4565b6040516302b97d6d60e21b81526001600160a01b03841690630ae5f5b490610a649087908690600401615c17565b60206040518083038186803b158015610a7c57600080fd5b505afa158015610a90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab49190615330565b90508760600151811015610ada5760405162461bcd60e51b815260040161084b9061576f565b6000808960200151610aee57600083610af2565b8260005b91509150610b01888a88612b70565b600e546001600160a01b038881169116148015610b1f575089608001515b15610b9b5760405163022c0d9f60e01b81526001600160a01b0386169063022c0d9f90610b56908590859030908a90600401615c30565b600060405180830381600087803b158015610b7057600080fd5b505af1158015610b84573d6000803e3d6000fd5b50505050610b968a60a0015184612cbb565b610c04565b60a08a015160405163022c0d9f60e01b81526001600160a01b0387169163022c0d9f91610bd19186918691908a90600401615c30565b600060405180830381600087803b158015610beb57600080fd5b505af1158015610bff573d6000803e3d6000fd5b505050505b50505050505050505050565b600f546001600160a01b03163314610c3a5760405162461bcd60e51b815260040161084b9061578d565b60005463ffffffff82811691161415610c655760405162461bcd60e51b815260040161084b906157ab565b6000805463ffffffff191663ffffffff83161790556040517f63e09f16584208fba1fc7ff64c62b00f07bec177c0d97ca6689891b1e77a35c790610caa908390615c67565b60405180910390a150565b600f546001600160a01b03163314610cdf5760405162461bcd60e51b815260040161084b9061578d565b600f546001600160a01b0382811691161415610d0d5760405162461bcd60e51b815260040161084b906157ab565b6001600160a01b038116610d335760405162461bcd60e51b815260040161084b90615823565b600f80546001600160a01b0319166001600160a01b0383161790556040517f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe290610caa90839061552d565b600f546001600160a01b03163314610da85760405162461bcd60e51b815260040161084b9061578d565b604051636702eca360e01b8152736336788a85f54d8856782d58c1ca63c7d384453190636702eca390610de2906000908590600401615ab8565b60006040518083038186803b158015610dfa57600080fd5b505af4158015610e0e573d6000803e3d6000fd5b5050505050565b610e1d614a1d565b604051634ce4436960e11b8152736336788a85f54d8856782d58c1ca63c7d3844531906399c886d290610e57906000908690600401615ab8565b6101206040518083038186803b158015610e7057600080fd5b505af4158015610e84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea8919061527b565b90505b919050565b604051631ae4448160e31b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063d722240890610eec90849086906004016158b4565b60206040518083038186803b158015610f0457600080fd5b505af4158015610f18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190614f4e565b600f546001600160a01b03163314610f665760405162461bcd60e51b815260040161084b9061578d565b6001600160a01b03821660009081526010602052604090205460ff1615158115151415610fa55760405162461bcd60e51b815260040161084b906157ab565b6001600160a01b03821660009081526010602052604090819020805460ff1916831515179055517f70af441dbb427737e6a5ef2cf5b664321011765ce1d19ce4a69cd024e69d4f2f90610ffb9084908490615677565b60405180910390a15050565b61100f614a80565b60405163ac1ecdb360e01b8152736336788a85f54d8856782d58c1ca63c7d38445319063ac1ecdb390611049906000908690600401615ab8565b6101606040518083038186803b15801561106257600080fd5b505af4158015611076573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190615011565b60106020526000908152604090205460ff1681565b3330146110ce5760405162461bcd60e51b815260040161084b9061578d565b426202a30082610100015163ffffffff160110156110fe5760405162461bcd60e51b815260040161084b906157e7565b600080600061111584600001518560200151612992565b9250925092506000600d73b28c804e3dacff80701bbbafd106dbfb416a5168636c5d9cf090918588604001516040518463ffffffff1660e01b815260040161115f9392919061588c565b60206040518083038186803b15801561117757600080fd5b505af415801561118b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111af9190615330565b90506000849050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156111f157600080fd5b505af1158015611205573d6000803e3d6000fd5b50505050600061122086886101200151896101400151612a52565b9050600087602001516112b457606088015160405163c7481b8f60e01b81526001600160a01b0385169163c7481b8f9161125f91908690600401615c17565b60206040518083038186803b15801561127757600080fd5b505afa15801561128b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112af9190615330565b611336565b606088015160405163d6945d8960e01b81526001600160a01b0385169163d6945d89916112e691908690600401615c17565b60206040518083038186803b1580156112fe57600080fd5b505afa158015611312573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113369190615330565b9050808410156113585760405162461bcd60e51b815260040161084b90615841565b808411156113ba57600e546001600160a01b03878116911614801561137e575087608001515b156113a05760a088015161139b906113968684612ddb565b612cbb565b6113ba565b60a08801516113ba9087906113b58785612ddb565b612b70565b60008089602001516113d25760008a606001516113da565b896060015160005b915091506113e9888a85612b70565b600e546001600160a01b038881169116148015611407575089608001515b15610b9b5760405163022c0d9f60e01b81526001600160a01b0386169063022c0d9f9061143e908590859030908a90600401615c30565b600060405180830381600087803b15801561145857600080fd5b505af115801561146c573d6000803e3d6000fd5b50505050610b968a60a001518b60600151612cbb565b61148e85878684612478565b61149a83878484612478565b505050505050565b600e546001600160a01b031690565b604051634dc1ffe760e11b8152600090736336788a85f54d8856782d58c1ca63c7d384453190639b83ffce906114ed9084908690600401615ab8565b60206040518083038186803b15801561150557600080fd5b505af4158015611519573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190614fa8565b604051634d95367160e11b8152600090736336788a85f54d8856782d58c1ca63c7d384453190639b2a6ce290610eec90849086906004016158b4565b600060115460011461159d5760405162461bcd60e51b815260040161084b906156f7565b6000601181905560405162c44ff160e31b8152736336788a85f54d8856782d58c1ca63c7d3844531916306227f88916115de91908690600d906004016158ff565b60006040518083038186803b1580156115f657600080fd5b505af415801561160a573d6000803e3d6000fd5b5050600154925050506001601155919050565b60115460011461163f5760405162461bcd60e51b815260040161084b906156f7565b60006011556002604051634dc1ffe760e11b8152736336788a85f54d8856782d58c1ca63c7d384453190639b83ffce90611680906000908690600401615ab8565b60206040518083038186803b15801561169857600080fd5b505af41580156116ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d09190614fa8565b60058111156116db57fe5b146116f85760405162461bcd60e51b815260040161084b90615805565b60405163317e626f60e21b81526000908190736336788a85f54d8856782d58c1ca63c7d38445319063c5f989bc906117369084908790600401615ab8565b604080518083038186803b15801561174d57600080fd5b505af4158015611761573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117859190614fc7565b60005491935063ffffffff908116925042916117b59162015180916117af918691811690612ddb16565b90612e0b565b106117d25760405162461bcd60e51b815260040161084b90615715565b6000838152600b60205260409020805460ff191660019081179091556117fd90839083908690612e52565b5050600160115550565b61180f614adc565b60405163117d7ab160e01b8152736336788a85f54d8856782d58c1ca63c7d38445319063117d7ab190611849906000908690600401615ab8565b6101a06040518083038186803b15801561186257600080fd5b505af4158015611876573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190615119565b60006011546001146118be5760405162461bcd60e51b815260040161084b906156f7565b60006011819055604051636587992160e01b8152736336788a85f54d8856782d58c1ca63c7d3844531916365879921916115de91908690600401615a0d565b60085490565b60055490565b3330146119285760405162461bcd60e51b815260040161084b9061578d565b426202a30082610100015163ffffffff160110156119585760405162461bcd60e51b815260040161084b906157e7565b8051604051630270f5c360e51b815260009182918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb8609161199991859190600401615ac6565b60606040518083038186803b1580156119b157600080fd5b505af41580156119c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e99190614d5f565b925092509250826001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a2a57600080fd5b505af1158015611a3e573d6000803e3d6000fd5b50505050611a5183848660200151612b70565b6080840151600090819081908015611a8d5750600e546001600160a01b0386811691161480611a8d5750600e546001600160a01b038581169116145b15611bd357600e5460a08801516000808052600a602052600080516020615d2b8339815191525460405163cf58beed60e01b81529193736195015b38773f468dd43620dd5a64e9bb63c2e39363cf58beed93611aff938c938c938f936001600160a01b0390921692909160040161555a565b60806040518083038186803b158015611b1757600080fd5b505af4158015611b2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b4f9190614f6a565b91965094509250905080611bcd5760a088015160405163032b310f60e51b815273b28c804e3dacff80701bbbafd106dbfb416a51689163656621e091611b9c91600d91899060040161588c565b60006040518083038186803b158015611bb457600080fd5b505af4158015611bc8573d6000803e3d6000fd5b505050505b50611c5a565b60a087015160405163226bf2d160e21b81526001600160a01b038816916389afcb4491611c03919060040161552d565b6040805180830381600087803b158015611c1c57600080fd5b505af1158015611c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c549190615348565b90925090505b86604001518210158015611c72575086606001518110155b611c8e5760405162461bcd60e51b815260040161084b90615751565b50505050505050565b60005463ffffffff1690565b60075490565b6000908152600b602052604090205460ff1690565b600f546001600160a01b03163314611ce85760405162461bcd60e51b815260040161084b9061578d565b60405163146bce4f60e31b8152736336788a85f54d8856782d58c1ca63c7d38445319063a35e727890611d26906000908790879087906004016158cb565b60006040518083038186803b158015611d3e57600080fd5b505af4158015611c8e573d6000803e3d6000fd5b600f546001600160a01b031681565b600f546001600160a01b03163314611d8b5760405162461bcd60e51b815260040161084b9061578d565b604051630fd1437d60e11b8152736336788a85f54d8856782d58c1ca63c7d384453190631fa286fa90610de2906000908590600401615ab8565b6001600160a01b03166000908152600a602052604090205490565b6000601154600114611e045760405162461bcd60e51b815260040161084b906156f7565b60006011819055604051638f0e6bef60e01b8152736336788a85f54d8856782d58c1ca63c7d384453191638f0e6bef916115de91908690600d90600401615923565b333014611e655760405162461bcd60e51b815260040161084b9061578d565b426202a30082610140015163ffffffff16011015611e955760405162461bcd60e51b815260040161084b906157e7565b6000806000806000611ea6866135e8565b945094509450945094508560c0015115612022578115611f705773b291730099d3ac9975abd4003ba3bd47401fd2fd6388aae0878686858a60600151611ef78b8d61016001518e6101800151612a52565b6040518663ffffffff1660e01b8152600401611f17959493929190615632565b604080518083038186803b158015611f2e57600080fd5b505af4158015611f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f669190615348565b9092509050612022565b80156120225773b291730099d3ac9975abd4003ba3bd47401fd2fd63dee184ee8685848a60800151611fad8b8d61016001518e6101800151612a52565b6040518663ffffffff1660e01b8152600401611fcd959493929190615632565b604080518083038186803b158015611fe457600080fd5b505af4158015611ff8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201c9190615348565b90925090505b811580159061203057508015155b156120ce5760e0860151604051633d2945e960e11b815273b291730099d3ac9975abd4003ba3bd47401fd2fd91637a528bd2916120799189918990899089908990600401615595565b604080518083038186803b15801561209057600080fd5b505af41580156120a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c89190615348565b90925090505b61149a8660e00151858585856138a6565b604051630994094b60e21b8152600090736336788a85f54d8856782d58c1ca63c7d384453190632650252c90610eec90849086906004016158b4565b612123614a80565b6040516311c8197f60e01b8152736336788a85f54d8856782d58c1ca63c7d3844531906311c8197f90611049906000908690600401615ab8565b600f546001600160a01b031633146121875760405162461bcd60e51b815260040161084b9061578d565b60405163153cc2fd60e31b8152736336788a85f54d8856782d58c1ca63c7d38445319063a9e617e890610de2906000908590600401615ab8565b60006011546001146121e55760405162461bcd60e51b815260040161084b906156f7565b6000601181905560405163758e99b360e01b8152736336788a85f54d8856782d58c1ca63c7d38445319163758e99b3916115de91908690600d906004016158ff565b6011546001146122495760405162461bcd60e51b815260040161084b906156f7565b60006011819055604051631ae4f06f60e01b81528190736336788a85f54d8856782d58c1ca63c7d384453190631ae4f06f9061228b9084908790600401615ab8565b604080518083038186803b1580156122a257600080fd5b505af41580156122b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122da9190614fc7565b63ffffffff16915091506117fd8282856000612e52565b6001600160a01b03166000908152600d602052604090205490565b6004546001600160a01b031690565b33301461233a5760405162461bcd60e51b815260040161084b9061578d565b612345838383612b70565b505050565b60405163317e626f60e21b81526000908190736336788a85f54d8856782d58c1ca63c7d38445319063c5f989bc906123889084908790600401615ab8565b604080518083038186803b15801561239f57600080fd5b505af41580156123b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123d79190614fc7565b91509150915091565b600f546001600160a01b0316331461240a5760405162461bcd60e51b815260040161084b9061578d565b60405163b2456a0760e01b8152736336788a85f54d8856782d58c1ca63c7d38445319063b2456a0790612446906000908690869060040161588c565b60006040518083038186803b15801561245e57600080fd5b505af415801561149a573d6000803e3d6000fd5b60015490565b3330146124975760405162461bcd60e51b815260040161084b9061578d565b600e546001600160a01b0385811691161480156124b15750805b156125d4576040516306c5d9cf60e41b815260009073b28c804e3dacff80701bbbafd106dbfb416a516890636c5d9cf0906124f590600d908990889060040161588c565b60206040518083038186803b15801561250d57600080fd5b505af4158015612521573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125459190615330565b600e54604051632e1a7d4d60e01b81529192506001600160a01b031690632e1a7d4d906125769084906004016158ab565b600060405180830381600087803b15801561259057600080fd5b505af11580156125a4573d6000803e3d6000fd5b5050600080525050600a602052600080516020615d2b833981519152546125ce90859083906138c8565b50612668565b6040516306c5d9cf60e41b8152612668908590859073b28c804e3dacff80701bbbafd106dbfb416a516890636c5d9cf09061261890600d9086908a9060040161588c565b60206040518083038186803b15801561263057600080fd5b505af4158015612644573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b59190615330565b50505050565b60405163014ef18960e11b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063029de31290610eec90849086906004016158b4565b60025490565b6011546001146126d25760405162461bcd60e51b815260040161084b906156f7565b60006011556040517f892cd8f5b436bd5fb7dac1f11aafb73345d892ba3e9fe09cd94d95ba84928e73906127099033908490615541565b60405180910390a160005a3360009081526010602052604081205491925090819060ff168061276257506000805260106020527f6e0956cda88cad152e89927e53611735b61a5c762d1428573c6931b0a5efcb015460ff165b905060005b848110156128e0576002546001016000908152600b602052604090205460ff16156127f9576040516305d4bd1160e01b8152736336788a85f54d8856782d58c1ca63c7d3844531906305d4bd11906127c4906000906004016158ab565b60006040518083038186803b1580156127dc57600080fd5b505af41580156127f0573d6000803e3d6000fd5b505050506128d8565b600080612806600061395a565b9092509050600082600481111561281957fe5b14806128255750428110155b156128315750506128e0565b838061284157506104b081014210155b61285d5760405162461bcd60e51b815260040161084b9061578d565b600194508482600481111561286e57fe5b14156128815761287c61397e565b6128d5565b600282600481111561288f57fe5b141561289d5761287c613c36565b60038260048111156128ab57fe5b14156128b95761287c613eaf565b60048260048111156128c757fe5b14156128d5576128d5614128565b50505b600101612767565b50811561295c57736336788a85f54d8856782d58c1ca63c7d3844531639db74df1600061290e5a8790612ddb565b6040518363ffffffff1660e01b815260040161292b929190615ab8565b60006040518083038186803b15801561294357600080fd5b505af4158015612957573d6000803e3d6000fd5b505050505b505060016011555050565b60065490565b60019190910180546001600160a01b0319166001600160a01b03909216919091179055565b6000806000806000806000736336788a85f54d8856782d58c1ca63c7d3844531634e1eb86090918a6040518363ffffffff1660e01b81526004016129d7929190615ac6565b60606040518083038186803b1580156129ef57600080fd5b505af4158015612a03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a279190614d5f565b92509250925060008088612a3c578383612a3f565b82845b9598509650939450505050509250925092565b60606000846001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b158015612a8f57600080fd5b505afa158015612aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ac79190614d43565b6001600160a01b0316638c09166e85856040518363ffffffff1660e01b8152600401612af4929190615ac6565b60206040518083038186803b158015612b0c57600080fd5b505afa158015612b20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b449190615330565b905080604051602001612b5791906158ab565b6040516020818303038152906040529150509392505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b60208310612bec5780518252601f199092019160209182019101612bcd565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612c4e576040519150601f19603f3d011682016040523d82523d6000602084013e612c53565b606091505b5091509150818015612c81575080511580612c815750808060200190516020811015612c7e57600080fd5b50515b610e0e576040805162461bcd60e51b815260206004808301919091526024820152635448303560e01b604482015290519081900360640190fd5b600e54604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d90612ceb9084906004016158ab565b600060405180830381600087803b158015612d0557600080fd5b505af1158015612d19573d6000803e3d6000fd5b50506000808052600a602052600080516020615d2b833981519152546040519193506001600160a01b0386169250908490612d539061552a565b600060405180830381858888f193505050503d8060008114612d91576040519150601f19603f3d011682016040523d82523d6000602084013e612d96565b606091505b50509050806123455760405163032b310f60e51b815273b28c804e3dacff80701bbbafd106dbfb416a51689063656621e090611d2690600d908790879060040161588c565b6000612e0483836040518060400160405280600481526020016329a6989960e11b815250614293565b9392505050565b80820182811015612e4c576040805162461bcd60e51b81526020600480830191909152602482015263534d344560e01b604482015290519081900360640190fd5b92915050565b6000846004811115612e6057fe5b1415612e7e5760405162461bcd60e51b815260040161084b9061585f565b600042612e8f856301e13380612e0b565b1090506001856004811115612ea057fe5b14156130785760405163117d7ab160e01b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063117d7ab190612ee29084908890600401615ab8565b6101a06040518083038186803b158015612efb57600080fd5b505af4158015612f0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f339190615119565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091612f7591859190600401615ac6565b60606040518083038186803b158015612f8d57600080fd5b505af4158015612fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc59190614d5f565b9250925050600084612fdb578360e00151612fe8565b600f546001600160a01b03165b9050613004818486602001518588604001518960a0015161432b565b6130205760405162461bcd60e51b815260040161084b90615733565b851561306f57600061304585610120015186610100015161449190919063ffffffff16565b905061305182826144e6565b61306d5760405162461bcd60e51b815260040161084b906157c9565b505b505050506135dd565b600285600481111561308657fe5b141561324a57604051634ce4436960e11b8152600090736336788a85f54d8856782d58c1ca63c7d3844531906399c886d2906130c89084908890600401615ab8565b6101206040518083038186803b1580156130e157600080fd5b505af41580156130f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613119919061527b565b8051604051630270f5c360e51b8152919250600091736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613158918591600401615ac6565b60606040518083038186803b15801561317057600080fd5b505af4158015613184573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a89190614d5f565b505090506000836131bd578260a001516131ca565b600f546001600160a01b03165b90506131db82828560200151614567565b6131f75760405162461bcd60e51b815260040161084b90615733565b841561324257600061321a8460e001518560c0015161449190919063ffffffff16565b905061322682826144e6565b61306f5760405162461bcd60e51b815260040161084b906157c9565b5050506135dd565b600385600481111561325857fe5b14156134055760405163ac1ecdb360e01b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063ac1ecdb39061329a9084908890600401615ab8565b6101606040518083038186803b1580156132b357600080fd5b505af41580156132c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132eb9190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb8609161332d91859190600401615ac6565b60606040518083038186803b15801561334557600080fd5b505af4158015613359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337d9190614d5f565b9250925050600084613393578360a001516133a0565b600f546001600160a01b03165b90506133c684602001516133b457836133b6565b825b8286604001518760800151614676565b6133e25760405162461bcd60e51b815260040161084b90615733565b851561306f5760006130458560e001518660c0015161449190919063ffffffff16565b600485600481111561341357fe5b14156135dd576040516311c8197f60e01b8152600090736336788a85f54d8856782d58c1ca63c7d3844531906311c8197f906134559084908890600401615ab8565b6101606040518083038186803b15801561346e57600080fd5b505af4158015613482573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134a69190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb860916134e891859190600401615ac6565b60606040518083038186803b15801561350057600080fd5b505af4158015613514573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135389190614d5f565b925092505060008461354e578360a0015161355b565b600f546001600160a01b03165b905061356f84602001516133b457836133b6565b61358b5760405162461bcd60e51b815260040161084b90615733565b85156135d85760006135ae8560e001518660c0015161449190919063ffffffff16565b90506135ba82826144e6565b6135d65760405162461bcd60e51b815260040161084b906157c9565b505b505050505b610e0e600084614795565b8051604051630270f5c360e51b81526000918291829182918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb8609161362d91859190600401615ac6565b60606040518083038186803b15801561364557600080fd5b505af4158015613659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367d9190614d5f565b60208901516040516306c5d9cf60e41b8152939850919650945060009173b28c804e3dacff80701bbbafd106dbfb416a516891636c5d9cf0916136c891600d918a919060040161588c565b60206040518083038186803b1580156136e057600080fd5b505af41580156136f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137189190615330565b60408089015190516306c5d9cf60e41b815291925060009173b28c804e3dacff80701bbbafd106dbfb416a516891636c5d9cf09161375e91600d918a919060040161588c565b60206040518083038186803b15801561377657600080fd5b505af415801561378a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137ae9190615330565b9050866001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156137eb57600080fd5b505af11580156137ff573d6000803e3d6000fd5b5050505060e0880151604051633d2945e960e11b815273b291730099d3ac9975abd4003ba3bd47401fd2fd91637a528bd291613847918b918b908b9089908990600401615595565b604080518083038186803b15801561385e57600080fd5b505af4158015613872573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138969190615348565b9799969850949694959350505050565b81156138b7576138b7848684612b70565b8015610e0e57610e0e838683612b70565b6040516000906001600160a01b038516908390859084818181858888f193505050503d8060008114613916576040519150601f19603f3d011682016040523d82523d6000602084013e61391b565b606091505b5050905080612668576040805162461bcd60e51b815260206004808301919091526024820152632a2419a360e11b604482015290519081900360640190fd5b60008061396e8384600201546001016147c8565b90925063ffffffff169050915091565b60005a60405163a81df10f60e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d38445319063a81df10f906139be9084906004016158ab565b6101a06040518083038186803b1580156139d757600080fd5b505af41580156139eb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a0f9190615119565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613a5191859190600401615ac6565b60606040518083038186803b158015613a6957600080fd5b505af4158015613a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613aa19190614d5f565b6001600160a01b038082166000908152600a602052604080822054928516825281205493965091945090925082913091613af491613ae891906117af9062012c6c90612e0b565b61012088015190612ddb565b604051634ed4967d60e11b90613b0e908990602401615ada565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613b4c919061550e565b60006040518083038160008787f1925050503d8060008114613b8a576040519150601f19603f3d011682016040523d82523d6000602084013e613b8f565b606091505b509092509050600182613bbd57613bba8660e00151868860200151878a604001518b60a0015161432b565b90505b613bc6816147fe565b600080613be38861012001518961010001518b8b60e0015161481f565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613c239392919061569d565b60405180910390a3505050505050505050565b60005a6040516313ed2f6160e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d3844531906313ed2f6190613c769084906004016158ab565b6101206040518083038186803b158015613c8f57600080fd5b505af4158015613ca3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cc7919061527b565b905060008030613cea613cdf62012c6c61d6d8612e0b565b60e086015190612ddb565b604051631a42443160e21b90613d04908790602401615ba0565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613d42919061550e565b60006040518083038160008787f1925050503d8060008114613d80576040519150601f19603f3d011682016040523d82523d6000602084013e613d85565b606091505b509092509050600182613e3a578351604051630270f5c360e51b8152600091736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613dcf91859190600401615ac6565b60606040518083038186803b158015613de757600080fd5b505af4158015613dfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e1f9190614d5f565b50509050613e36818660a001518760200151614567565b9150505b613e43816147fe565b600080613e5e8660e001518760c00151898960a0015161481f565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613e9e9392919061569d565b60405180910390a350505050505050565b60005a604051632e9d30e160e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d384453190632e9d30e190613eef9084906004016158ab565b6101606040518083038186803b158015613f0857600080fd5b505af4158015613f1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f409190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613f8291859190600401615ac6565b60606040518083038186803b158015613f9a57600080fd5b505af4158015613fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fd29190614d5f565b9250925050600080306001600160a01b03166140316140266000600a01600089602001516140005788614002565b875b6001600160a01b0316815260208101919091526040016000205462012c6c90612e0b565b60e088015190612ddb565b604051630b65604d60e01b9061404b90899060240161587d565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614089919061550e565b60006040518083038160008787f1925050503d80600081146140c7576040519150601f19603f3d011682016040523d82523d6000602084013e6140cc565b606091505b5090925090506001826141045761410186602001516140eb57856140ed565b845b8760a0015188604001518960800151614676565b90505b61410d816147fe565b600080613be38860e001518960c001518b8b60a0015161481f565b60005a60405163a1ba139560e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d38445319063a1ba1395906141689084906004016158ab565b6101606040518083038186803b15801561418157600080fd5b505af4158015614195573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141b99190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb860916141fb91859190600401615ac6565b60606040518083038186803b15801561421357600080fd5b505af4158015614227573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061424b9190614d5f565b9250925050600080306001600160a01b03166142796140266000600a01600089602001516140005788614002565b604051633c763c1760e01b9061404b90899060240161587d565b81830381848211156143235760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156142e85781810151838201526020016142d0565b50505050905090810190601f1680156143155780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509392505050565b6001600160a01b038381166000908152600a6020526040808220549288168252812054909182918291309161435f91612e0b565b604051633ed76f1760e01b90614383908d908d908d908d908d908d906024016155cf565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516143c1919061550e565b60006040518083038160008787f1925050503d80600081146143ff576040519150601f19603f3d011682016040523d82523d6000602084013e614404565b606091505b50915091508161448557876001600160a01b0316896001600160a01b0316600080516020615d0b8339815191528984604051614441929190615c17565b60405180910390a3856001600160a01b0316896001600160a01b0316600080516020615d0b833981519152878460405161447c929190615c17565b60405180910390a35b50979650505050505050565b60008115806144ac575050808202828282816144a957fe5b04145b612e4c576040805162461bcd60e51b81526020600480830191909152602482015263534d324160e01b604482015290519081900360640190fd5b6000816144f557506001612e4c565b60008052600a602052600080516020615d2b8339815191525461451b90849084906148af565b9050801515836001600160a01b03167fdbef2fc26e7694e7a1c5a4801b1ad144136d149cf76f310a780689b4087f0ffe8460405161455991906158ab565b60405180910390a392915050565b60008161457657506001612e04565b600080306001600160a01b031661d6d863c9cd976060e01b88888860006040516024016145a69493929190615609565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516145e4919061550e565b60006040518083038160008787f1925050503d8060008114614622576040519150601f19603f3d011682016040523d82523d6000602084013e614627565b606091505b50915091508161466d57856001600160a01b0316856001600160a01b0316600080516020615d0b8339815191528684604051614664929190615c17565b60405180910390a35b50949350505050565b6000826146855750600161478d565b6001600160a01b0385166000908152600a60205260408082205490518291309163e5b1be6560e01b906146c2908b908b908b908b90602401615609565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614700919061550e565b60006040518083038160008787f1925050503d806000811461473e576040519150601f19603f3d011682016040523d82523d6000602084013e614743565b606091505b50915091508161478957866001600160a01b0316866001600160a01b0316600080516020615d0b8339815191528784604051614780929190615c17565b60405180910390a35b5090505b949350505050565b6000908152600391820160205260408120818155600181018290556002810180546001600160e81b031916905590910155565b60008181526003830160205260408120805463ffffffff610100820416919060ff166147f38161490d565b935050509250929050565b806148125761480d600061497d565b61481c565b61481c60006149d0565b50565b6000808061482d8787614491565b90506148406155946117af5a8890612ddb565b92506000614865826148606000600601548761449190919063ffffffff16565b614a07565b90506148718282612ddb565b925061487d33826144e6565b6148995760405162461bcd60e51b815260040161084b906157c9565b6148a385846144e6565b50505094509492505050565b6040516000906001600160a01b038516908390859084818181858888f193505050503d80600081146148fd576040519150601f19603f3d011682016040523d82523d6000602084013e614902565b606091505b509095945050505050565b6000600182141561492057506001610eab565b600282141561493157506002610eab565b600382141561494257506004610eab565b600482141561495357506004610eab565b600582141561496457506003610eab565b600682141561497557506003610eab565b506000919050565b600281015460009081526003820160205260409020805465010000000000900460ff16156149ac5760036149af565b60025b815460ff91909116650100000000000265ff00000000001990911617905550565b60028082015460009081526003928301602052604081208181556001810182905591820180546001600160e81b0319169055910155565b6000818310614a165781612e04565b5090919050565b604051806101200160405280600063ffffffff16815260200160008152602001600081526020016000815260200160001515815260200160006001600160a01b031681526020016000815260200160008152602001600063ffffffff1681525090565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b604051806101a00160405280600063ffffffff1681526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160006001600160a01b031681526020016000815260200160008152602001600063ffffffff16815260200160008152602001600063ffffffff1681525090565b8035610eab81615cc8565b8051610eab81615cc8565b8035610eab81615cdd565b8051610eab81615cdd565b6000610160808385031215614ba2578182fd5b614bab81615c78565b915050614bb782614d11565b8152614bc560208301614b79565b60208201526040820135604082015260608201356060820152614bea60808301614b79565b6080820152614bfb60a08301614b63565b60a082015260c082013560c082015260e082013560e0820152610100614c22818401614d11565b908201526101208281013590820152610140614c3f818401614d11565b9082015292915050565b6000610160808385031215614c5c578182fd5b614c6581615c78565b915050614c7182614d1c565b8152614c7f60208301614b84565b60208201526040820151604082015260608201516060820152614ca460808301614b84565b6080820152614cb560a08301614b6e565b60a082015260c082015160c082015260e082015160e0820152610100614cdc818401614d1c565b908201526101208281015190820152610140614c3f818401614d1c565b60006101008284031215614d0b578081fd5b50919050565b8035610eab81615cf8565b8051610eab81615cf8565b600060208284031215614d38578081fd5b8135612e0481615cc8565b600060208284031215614d54578081fd5b8151612e0481615cc8565b600080600060608486031215614d73578182fd5b8351614d7e81615cc8565b6020850151909350614d8f81615cc8565b6040850151909250614da081615cc8565b809150509250925092565b600080600060608486031215614dbf578081fd5b8335614dca81615cc8565b92506020840135614dda81615cc8565b929592945050506040919091013590565b60008060008060008060c08789031215614e03578384fd5b8635614e0e81615cc8565b95506020870135614e1e81615cc8565b9450604087013593506060870135614e3581615cc8565b92506080870135915060a0870135614e4c81615cdd565b809150509295509295509295565b60008060008060808587031215614e6f578182fd5b8435614e7a81615cc8565b93506020850135614e8a81615cc8565b9250604085013591506060850135614ea181615cdd565b939692955090935050565b60008060408385031215614ebe578182fd5b8235614ec981615cc8565b91506020830135614ed981615cdd565b809150509250929050565b600080600060608486031215614ef8578081fd5b8335614f0381615cc8565b92506020840135614f1381615ceb565b91506040840135614da081615cdd565b60008060408385031215614f35578182fd5b8235614f4081615cc8565b946020939093013593505050565b600060208284031215614f5f578081fd5b8151612e0481615cdd565b60008060008060808587031215614f7f578182fd5b8451614f8a81615cdd565b60208601516040870151606090970151919890975090945092505050565b600060208284031215614fb9578081fd5b815160068110612e04578182fd5b60008060408385031215614fd9578182fd5b8251614fe481615ceb565b6020840151909250614ed981615cf8565b60006101608284031215615007578081fd5b612e048383614b8f565b60006101608284031215615023578081fd5b612e048383614c49565b6000610100828403121561503f578081fd5b612e048383614cf9565b60006101a080838503121561505c578182fd5b61506581615c78565b905061507083614d11565b8152602083013560208201526040830135604082015260608301356060820152608083013560808201526150a660a08401614b79565b60a08201526150b760c08401614b79565b60c08201526150c860e08401614b63565b60e0820152610100838101359082015261012080840135908201526101406150f1818501614d11565b90820152610160838101359082015261018061510e818501614d11565b908201529392505050565b60006101a080838503121561512c578182fd5b61513581615c78565b905061514083614d1c565b81526020830151602082015260408301516040820152606083015160608201526080830151608082015261517660a08401614b84565b60a082015261518760c08401614b84565b60c082015261519860e08401614b6e565b60e0820152610100838101519082015261012080840151908201526101406151c1818501614d1c565b90820152610160838101519082015261018061510e818501614d1c565b60006101608284031215614d0b578081fd5b6000610120808385031215615203578182fd5b61520c81615c78565b905061521783614d11565b815260208301356020820152604083013560408201526060830135606082015261524360808401614b79565b608082015261525460a08401614b63565b60a082015260c083013560c082015260e083013560e082015261010061510e818501614d11565b600061012080838503121561528e578182fd5b61529781615c78565b90506152a283614d1c565b81526020830151602082015260408301516040820152606083015160608201526152ce60808401614b84565b60808201526152df60a08401614b6e565b60a082015260c083015160c082015260e083015160e082015261010061510e818501614d1c565b60006101208284031215614d0b578081fd5b600060208284031215615329578081fd5b5035919050565b600060208284031215615341578081fd5b5051919050565b6000806040838503121561535a578182fd5b505080516020909101519092909150565b60006020828403121561537c578081fd5b8135612e0481615cf8565b6001600160a01b03169052565b15159052565b600081518084526153b2816020860160208601615c9c565b601f01601f19169290920160200192915050565b600581106153d057fe5b9052565b6153df828251615504565b60208101516153f16020840182615394565b50604081015160408301526060810151606083015260808101516154186080840182615394565b5060a081015161542b60a0840182615387565b5060c081015160c083015260e081015160e08301526101008082015161545382850182615504565b505061012081810151908301526101408082015161266882850182615504565b803561547e81615cc8565b6001600160a01b03908116835260208201359061549a82615cc8565b166020830152604081810135908301526060808201359083015260808101356154c281615cdd565b1515608083015260a08101356154d781615cc8565b6154e460a0840182615387565b5060c081013560c08301526154fb60e08201614d11565b61234560e08401825b63ffffffff169052565b60008251615520818460208701615c9c565b9190910192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039687168152948616602086015292851660408501529084166060840152909216608082015260a081019190915260c00190565b6001600160a01b0396871681529486166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b6001600160a01b0396871681529486166020860152604085019390935293166060830152608082019290925290151560a082015260c00190565b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061566c9083018461539a565b979650505050505050565b6001600160a01b039290921682521515602082015260400190565b901515815260200190565b6000606082526156b0606083018661539a565b60208301949094525060400152919050565b60208101600683106156d057fe5b91905290565b604081016156e482856153c6565b63ffffffff831660208301529392505050565b6020808252600490820152632a22181b60e11b604082015260600190565b6020808252600490820152635444314360e01b604082015260600190565b60208082526004908201526315110c4d60e21b604082015260600190565b6020808252600490820152635444303360e01b604082015260600190565b6020808252600490820152635444333760e01b604082015260600190565b6020808252600490820152630544430360e41b604082015260600190565b6020808252600490820152635444303160e01b604082015260600190565b6020808252600490820152630544434360e41b604082015260600190565b60208082526004908201526315110c0d60e21b604082015260600190565b6020808252600490820152632a221a9960e11b604082015260600190565b6020808252600490820152632a22181960e11b604082015260600190565b6020808252600490820152630a88860760e31b604082015260600190565b6020808252600490820152635444343160e01b604082015260600190565b6101608101612e4c82846153d4565b9283526001600160a01b03919091166020830152604082015260600190565b90815260200190565b9182526001600160a01b0316602082015260400190565b8481526001600160a01b0384166020820152608081016158ee60408301856153c6565b821515606083015295945050505050565b83815261014081016159146020830185615473565b82610120830152949350505050565b8381526101a081016159406020830161593b86614b63565b615387565b61594c60208501614b63565b6159596040840182615387565b506040840135606083015260608401356080830152608084013560a083015260a084013560c083015261598e60c08501614b79565b61599b60e0840182615394565b506159a860e08501614b79565b6101006159b781850183615394565b6159c2818701614b63565b9150506101206159d481850183615387565b61014091508086013582850152506159ed818601614d11565b90506159fd610160840182615504565b5082610180830152949350505050565b8281526101408101615a256020830161593b85614b63565b615a3160208401614b63565b615a3e6040840182615387565b506040830135606083015260608301356080830152608083013560a0830152615a6960a08401614b79565b615a7660c0840182615394565b50615a8360c08401614b63565b615a9060e0840182615387565b5061010060e084013581840152615aa8818501614d11565b9050614323610120840182615504565b918252602082015260400190565b91825263ffffffff16602082015260400190565b60006101a082019050615aee828451615504565b6020830151602083015260408301516040830152606083015160608301526080830151608083015260a0830151615b2860a0840182615394565b5060c0830151615b3b60c0840182615394565b5060e0830151615b4e60e0840182615387565b506101008381015190830152610120808401519083015261014080840151615b7882850182615504565b5050610160838101519083015261018080840151615b9882850182615504565b505092915050565b60006101208201905063ffffffff835116825260208301516020830152604083015160408301526060830151606083015260808301511515608083015260a0830151615bef60a0840182615387565b5060c083015160c083015260e083015160e083015261010080840151615b9882850182615504565b60008382526040602083015261478d604083018461539a565b600085825284602083015260018060a01b038416604083015260806060830152615c5d608083018461539a565b9695505050505050565b63ffffffff91909116815260200190565b60405181810167ffffffffffffffff81118282101715615c9457fe5b604052919050565b60005b83811015615cb7578181015183820152602001615c9f565b838111156126685750506000910152565b6001600160a01b038116811461481c57600080fd5b801515811461481c57600080fd5b6005811061481c57600080fd5b63ffffffff8116811461481c57600080fdfe786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b21159213da86008ba1c6922daee3e07db95305ef49ebced9f5467a0b8613fcc6b343e3a26469706673582212204869fe8a86a81d32e462924c6375438fb998a95decb6fe160a341c323c1eee6f64736f6c63430007060033000000000000000000000000c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c6000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000003a1d749fa4a9e650fce844ff1c58c5faf7e2a9d1
Deployed Bytecode
0x6080604052600436106102815760003560e01c806377632ec21161014f578063be581304116100c1578063e30a49931161007a578063e30a49931461078d578063e5b1be65146107a2578063e5e7988e146107c2578063e6a0cc94146107e2578063fe0d94c1146107f7578063fe173b971461081757610288565b8063be581304146106ca578063bf6b874e146106ea578063c45a01551461070a578063c9cd97601461071f578063d09ef2411461073f578063d22e92421461076d57610288565b80639d08ebb5116101135780639d08ebb5146106245780639da92cfa14610637578063af482b5814610657578063b1af1bda14610677578063b32ac93614610697578063ba4d5312146106b757610288565b806377632ec21461058f5780637f6a1caf146105af5780638da5cb5b146105cf57806394531713146105e45780639718f6271461060457610288565b80633fc8cef3116101f3578063576b332b116101ac578063576b332b146104fb57806357a62a4f1461050e5780635e45da2314610523578063690910c4146105385780636a42b8f8146105585780636de3c67c1461057a57610288565b80633fc8cef31461041f57806345fa8aae146104415780634c0160161461046e5780635051349a1461048e578063514fcac7146104ae57806354df6d74146104ce57610288565b806320a68fab1161024557806320a68fab14610345578063342aa8b514610372578063390ce0d3146103925780633bbac579146103bf5780633c763c17146103df5780633ed76f17146103ff57610288565b80630b65604d1461028d57806310348665146102af57806313af4035146102cf5780631776834a146102ef57806317818a5c1461030f57610288565b3661028857005b600080fd5b34801561029957600080fd5b506102ad6102a8366004614ff5565b61082c565b005b3480156102bb57600080fd5b506102ad6102ca36600461536b565b610c10565b3480156102db57600080fd5b506102ad6102ea366004614d27565b610cb5565b3480156102fb57600080fd5b506102ad61030a366004615318565b610d7e565b34801561031b57600080fd5b5061032f61032a366004615318565b610e15565b60405161033c9190615ba0565b60405180910390f35b34801561035157600080fd5b50610365610360366004614d27565b610eb0565b60405161033c9190615692565b34801561037e57600080fd5b506102ad61038d366004614eac565b610f3c565b34801561039e57600080fd5b506103b26103ad366004615318565b611007565b60405161033c919061587d565b3480156103cb57600080fd5b506103656103da366004614d27565b61109a565b3480156103eb57600080fd5b506102ad6103fa366004614ff5565b6110af565b34801561040b57600080fd5b506102ad61041a366004614deb565b611482565b34801561042b57600080fd5b506104346114a2565b60405161033c919061552d565b34801561044d57600080fd5b5061046161045c366004615318565b6114b1565b60405161033c91906156c2565b34801561047a57600080fd5b50610365610489366004614d27565b61153d565b6104a161049c36600461502d565b611579565b60405161033c91906158ab565b3480156104ba57600080fd5b506102ad6104c9366004615318565b61161d565b3480156104da57600080fd5b506104ee6104e9366004615318565b611807565b60405161033c9190615ada565b6104a1610509366004615306565b61189a565b34801561051a57600080fd5b506104a16118fd565b34801561052f57600080fd5b506104a1611903565b34801561054457600080fd5b506102ad6105533660046151f0565b611909565b34801561056457600080fd5b5061056d611c97565b60405161033c9190615c67565b34801561058657600080fd5b506104a1611ca3565b34801561059b57600080fd5b506103656105aa366004615318565b611ca9565b3480156105bb57600080fd5b506102ad6105ca366004614ee4565b611cbe565b3480156105db57600080fd5b50610434611d52565b3480156105f057600080fd5b506102ad6105ff366004615318565b611d61565b34801561061057600080fd5b506104a161061f366004614d27565b611dc5565b6104a16106323660046151de565b611de0565b34801561064357600080fd5b506102ad610652366004615049565b611e46565b34801561066357600080fd5b50610365610672366004614d27565b6120df565b34801561068357600080fd5b506103b2610692366004615318565b61211b565b3480156106a357600080fd5b506102ad6106b2366004615318565b61215d565b6104a16106c536600461502d565b6121c1565b3480156106d657600080fd5b506102ad6106e5366004615318565b612227565b3480156106f657600080fd5b506104a1610705366004614d27565b6122f1565b34801561071657600080fd5b5061043461230c565b34801561072b57600080fd5b506102ad61073a366004614dab565b61231b565b34801561074b57600080fd5b5061075f61075a366004615318565b61234a565b60405161033c9291906156d6565b34801561077957600080fd5b506102ad610788366004614f23565b6123e0565b34801561079957600080fd5b506104a1612472565b3480156107ae57600080fd5b506102ad6107bd366004614e5a565b612478565b3480156107ce57600080fd5b506103656107dd366004614d27565b61266e565b3480156107ee57600080fd5b506104a16126aa565b34801561080357600080fd5b506102ad610812366004615318565b6126b0565b34801561082357600080fd5b506104a1612967565b3330146108545760405162461bcd60e51b815260040161084b9061578d565b60405180910390fd5b426202a30082610100015163ffffffff160110156108845760405162461bcd60e51b815260040161084b906157e7565b600080600061089b84600001518560200151612992565b9250925092506000600d73b28c804e3dacff80701bbbafd106dbfb416a5168636c5d9cf090918588604001516040518463ffffffff1660e01b81526004016108e59392919061588c565b60206040518083038186803b1580156108fd57600080fd5b505af4158015610911573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109359190615330565b90506000849050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561097757600080fd5b505af115801561098b573d6000803e3d6000fd5b5050505060006109a686886101200151896101400151612a52565b905060008760200151610a3657604051632b9b015d60e01b81526001600160a01b03841690632b9b015d906109e19087908690600401615c17565b60206040518083038186803b1580156109f957600080fd5b505afa158015610a0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a319190615330565b610ab4565b6040516302b97d6d60e21b81526001600160a01b03841690630ae5f5b490610a649087908690600401615c17565b60206040518083038186803b158015610a7c57600080fd5b505afa158015610a90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab49190615330565b90508760600151811015610ada5760405162461bcd60e51b815260040161084b9061576f565b6000808960200151610aee57600083610af2565b8260005b91509150610b01888a88612b70565b600e546001600160a01b038881169116148015610b1f575089608001515b15610b9b5760405163022c0d9f60e01b81526001600160a01b0386169063022c0d9f90610b56908590859030908a90600401615c30565b600060405180830381600087803b158015610b7057600080fd5b505af1158015610b84573d6000803e3d6000fd5b50505050610b968a60a0015184612cbb565b610c04565b60a08a015160405163022c0d9f60e01b81526001600160a01b0387169163022c0d9f91610bd19186918691908a90600401615c30565b600060405180830381600087803b158015610beb57600080fd5b505af1158015610bff573d6000803e3d6000fd5b505050505b50505050505050505050565b600f546001600160a01b03163314610c3a5760405162461bcd60e51b815260040161084b9061578d565b60005463ffffffff82811691161415610c655760405162461bcd60e51b815260040161084b906157ab565b6000805463ffffffff191663ffffffff83161790556040517f63e09f16584208fba1fc7ff64c62b00f07bec177c0d97ca6689891b1e77a35c790610caa908390615c67565b60405180910390a150565b600f546001600160a01b03163314610cdf5760405162461bcd60e51b815260040161084b9061578d565b600f546001600160a01b0382811691161415610d0d5760405162461bcd60e51b815260040161084b906157ab565b6001600160a01b038116610d335760405162461bcd60e51b815260040161084b90615823565b600f80546001600160a01b0319166001600160a01b0383161790556040517f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe290610caa90839061552d565b600f546001600160a01b03163314610da85760405162461bcd60e51b815260040161084b9061578d565b604051636702eca360e01b8152736336788a85f54d8856782d58c1ca63c7d384453190636702eca390610de2906000908590600401615ab8565b60006040518083038186803b158015610dfa57600080fd5b505af4158015610e0e573d6000803e3d6000fd5b5050505050565b610e1d614a1d565b604051634ce4436960e11b8152736336788a85f54d8856782d58c1ca63c7d3844531906399c886d290610e57906000908690600401615ab8565b6101206040518083038186803b158015610e7057600080fd5b505af4158015610e84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea8919061527b565b90505b919050565b604051631ae4448160e31b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063d722240890610eec90849086906004016158b4565b60206040518083038186803b158015610f0457600080fd5b505af4158015610f18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190614f4e565b600f546001600160a01b03163314610f665760405162461bcd60e51b815260040161084b9061578d565b6001600160a01b03821660009081526010602052604090205460ff1615158115151415610fa55760405162461bcd60e51b815260040161084b906157ab565b6001600160a01b03821660009081526010602052604090819020805460ff1916831515179055517f70af441dbb427737e6a5ef2cf5b664321011765ce1d19ce4a69cd024e69d4f2f90610ffb9084908490615677565b60405180910390a15050565b61100f614a80565b60405163ac1ecdb360e01b8152736336788a85f54d8856782d58c1ca63c7d38445319063ac1ecdb390611049906000908690600401615ab8565b6101606040518083038186803b15801561106257600080fd5b505af4158015611076573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190615011565b60106020526000908152604090205460ff1681565b3330146110ce5760405162461bcd60e51b815260040161084b9061578d565b426202a30082610100015163ffffffff160110156110fe5760405162461bcd60e51b815260040161084b906157e7565b600080600061111584600001518560200151612992565b9250925092506000600d73b28c804e3dacff80701bbbafd106dbfb416a5168636c5d9cf090918588604001516040518463ffffffff1660e01b815260040161115f9392919061588c565b60206040518083038186803b15801561117757600080fd5b505af415801561118b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111af9190615330565b90506000849050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156111f157600080fd5b505af1158015611205573d6000803e3d6000fd5b50505050600061122086886101200151896101400151612a52565b9050600087602001516112b457606088015160405163c7481b8f60e01b81526001600160a01b0385169163c7481b8f9161125f91908690600401615c17565b60206040518083038186803b15801561127757600080fd5b505afa15801561128b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112af9190615330565b611336565b606088015160405163d6945d8960e01b81526001600160a01b0385169163d6945d89916112e691908690600401615c17565b60206040518083038186803b1580156112fe57600080fd5b505afa158015611312573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113369190615330565b9050808410156113585760405162461bcd60e51b815260040161084b90615841565b808411156113ba57600e546001600160a01b03878116911614801561137e575087608001515b156113a05760a088015161139b906113968684612ddb565b612cbb565b6113ba565b60a08801516113ba9087906113b58785612ddb565b612b70565b60008089602001516113d25760008a606001516113da565b896060015160005b915091506113e9888a85612b70565b600e546001600160a01b038881169116148015611407575089608001515b15610b9b5760405163022c0d9f60e01b81526001600160a01b0386169063022c0d9f9061143e908590859030908a90600401615c30565b600060405180830381600087803b15801561145857600080fd5b505af115801561146c573d6000803e3d6000fd5b50505050610b968a60a001518b60600151612cbb565b61148e85878684612478565b61149a83878484612478565b505050505050565b600e546001600160a01b031690565b604051634dc1ffe760e11b8152600090736336788a85f54d8856782d58c1ca63c7d384453190639b83ffce906114ed9084908690600401615ab8565b60206040518083038186803b15801561150557600080fd5b505af4158015611519573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190614fa8565b604051634d95367160e11b8152600090736336788a85f54d8856782d58c1ca63c7d384453190639b2a6ce290610eec90849086906004016158b4565b600060115460011461159d5760405162461bcd60e51b815260040161084b906156f7565b6000601181905560405162c44ff160e31b8152736336788a85f54d8856782d58c1ca63c7d3844531916306227f88916115de91908690600d906004016158ff565b60006040518083038186803b1580156115f657600080fd5b505af415801561160a573d6000803e3d6000fd5b5050600154925050506001601155919050565b60115460011461163f5760405162461bcd60e51b815260040161084b906156f7565b60006011556002604051634dc1ffe760e11b8152736336788a85f54d8856782d58c1ca63c7d384453190639b83ffce90611680906000908690600401615ab8565b60206040518083038186803b15801561169857600080fd5b505af41580156116ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d09190614fa8565b60058111156116db57fe5b146116f85760405162461bcd60e51b815260040161084b90615805565b60405163317e626f60e21b81526000908190736336788a85f54d8856782d58c1ca63c7d38445319063c5f989bc906117369084908790600401615ab8565b604080518083038186803b15801561174d57600080fd5b505af4158015611761573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117859190614fc7565b60005491935063ffffffff908116925042916117b59162015180916117af918691811690612ddb16565b90612e0b565b106117d25760405162461bcd60e51b815260040161084b90615715565b6000838152600b60205260409020805460ff191660019081179091556117fd90839083908690612e52565b5050600160115550565b61180f614adc565b60405163117d7ab160e01b8152736336788a85f54d8856782d58c1ca63c7d38445319063117d7ab190611849906000908690600401615ab8565b6101a06040518083038186803b15801561186257600080fd5b505af4158015611876573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea89190615119565b60006011546001146118be5760405162461bcd60e51b815260040161084b906156f7565b60006011819055604051636587992160e01b8152736336788a85f54d8856782d58c1ca63c7d3844531916365879921916115de91908690600401615a0d565b60085490565b60055490565b3330146119285760405162461bcd60e51b815260040161084b9061578d565b426202a30082610100015163ffffffff160110156119585760405162461bcd60e51b815260040161084b906157e7565b8051604051630270f5c360e51b815260009182918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb8609161199991859190600401615ac6565b60606040518083038186803b1580156119b157600080fd5b505af41580156119c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e99190614d5f565b925092509250826001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a2a57600080fd5b505af1158015611a3e573d6000803e3d6000fd5b50505050611a5183848660200151612b70565b6080840151600090819081908015611a8d5750600e546001600160a01b0386811691161480611a8d5750600e546001600160a01b038581169116145b15611bd357600e5460a08801516000808052600a602052600080516020615d2b8339815191525460405163cf58beed60e01b81529193736195015b38773f468dd43620dd5a64e9bb63c2e39363cf58beed93611aff938c938c938f936001600160a01b0390921692909160040161555a565b60806040518083038186803b158015611b1757600080fd5b505af4158015611b2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b4f9190614f6a565b91965094509250905080611bcd5760a088015160405163032b310f60e51b815273b28c804e3dacff80701bbbafd106dbfb416a51689163656621e091611b9c91600d91899060040161588c565b60006040518083038186803b158015611bb457600080fd5b505af4158015611bc8573d6000803e3d6000fd5b505050505b50611c5a565b60a087015160405163226bf2d160e21b81526001600160a01b038816916389afcb4491611c03919060040161552d565b6040805180830381600087803b158015611c1c57600080fd5b505af1158015611c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c549190615348565b90925090505b86604001518210158015611c72575086606001518110155b611c8e5760405162461bcd60e51b815260040161084b90615751565b50505050505050565b60005463ffffffff1690565b60075490565b6000908152600b602052604090205460ff1690565b600f546001600160a01b03163314611ce85760405162461bcd60e51b815260040161084b9061578d565b60405163146bce4f60e31b8152736336788a85f54d8856782d58c1ca63c7d38445319063a35e727890611d26906000908790879087906004016158cb565b60006040518083038186803b158015611d3e57600080fd5b505af4158015611c8e573d6000803e3d6000fd5b600f546001600160a01b031681565b600f546001600160a01b03163314611d8b5760405162461bcd60e51b815260040161084b9061578d565b604051630fd1437d60e11b8152736336788a85f54d8856782d58c1ca63c7d384453190631fa286fa90610de2906000908590600401615ab8565b6001600160a01b03166000908152600a602052604090205490565b6000601154600114611e045760405162461bcd60e51b815260040161084b906156f7565b60006011819055604051638f0e6bef60e01b8152736336788a85f54d8856782d58c1ca63c7d384453191638f0e6bef916115de91908690600d90600401615923565b333014611e655760405162461bcd60e51b815260040161084b9061578d565b426202a30082610140015163ffffffff16011015611e955760405162461bcd60e51b815260040161084b906157e7565b6000806000806000611ea6866135e8565b945094509450945094508560c0015115612022578115611f705773b291730099d3ac9975abd4003ba3bd47401fd2fd6388aae0878686858a60600151611ef78b8d61016001518e6101800151612a52565b6040518663ffffffff1660e01b8152600401611f17959493929190615632565b604080518083038186803b158015611f2e57600080fd5b505af4158015611f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f669190615348565b9092509050612022565b80156120225773b291730099d3ac9975abd4003ba3bd47401fd2fd63dee184ee8685848a60800151611fad8b8d61016001518e6101800151612a52565b6040518663ffffffff1660e01b8152600401611fcd959493929190615632565b604080518083038186803b158015611fe457600080fd5b505af4158015611ff8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201c9190615348565b90925090505b811580159061203057508015155b156120ce5760e0860151604051633d2945e960e11b815273b291730099d3ac9975abd4003ba3bd47401fd2fd91637a528bd2916120799189918990899089908990600401615595565b604080518083038186803b15801561209057600080fd5b505af41580156120a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c89190615348565b90925090505b61149a8660e00151858585856138a6565b604051630994094b60e21b8152600090736336788a85f54d8856782d58c1ca63c7d384453190632650252c90610eec90849086906004016158b4565b612123614a80565b6040516311c8197f60e01b8152736336788a85f54d8856782d58c1ca63c7d3844531906311c8197f90611049906000908690600401615ab8565b600f546001600160a01b031633146121875760405162461bcd60e51b815260040161084b9061578d565b60405163153cc2fd60e31b8152736336788a85f54d8856782d58c1ca63c7d38445319063a9e617e890610de2906000908590600401615ab8565b60006011546001146121e55760405162461bcd60e51b815260040161084b906156f7565b6000601181905560405163758e99b360e01b8152736336788a85f54d8856782d58c1ca63c7d38445319163758e99b3916115de91908690600d906004016158ff565b6011546001146122495760405162461bcd60e51b815260040161084b906156f7565b60006011819055604051631ae4f06f60e01b81528190736336788a85f54d8856782d58c1ca63c7d384453190631ae4f06f9061228b9084908790600401615ab8565b604080518083038186803b1580156122a257600080fd5b505af41580156122b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122da9190614fc7565b63ffffffff16915091506117fd8282856000612e52565b6001600160a01b03166000908152600d602052604090205490565b6004546001600160a01b031690565b33301461233a5760405162461bcd60e51b815260040161084b9061578d565b612345838383612b70565b505050565b60405163317e626f60e21b81526000908190736336788a85f54d8856782d58c1ca63c7d38445319063c5f989bc906123889084908790600401615ab8565b604080518083038186803b15801561239f57600080fd5b505af41580156123b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123d79190614fc7565b91509150915091565b600f546001600160a01b0316331461240a5760405162461bcd60e51b815260040161084b9061578d565b60405163b2456a0760e01b8152736336788a85f54d8856782d58c1ca63c7d38445319063b2456a0790612446906000908690869060040161588c565b60006040518083038186803b15801561245e57600080fd5b505af415801561149a573d6000803e3d6000fd5b60015490565b3330146124975760405162461bcd60e51b815260040161084b9061578d565b600e546001600160a01b0385811691161480156124b15750805b156125d4576040516306c5d9cf60e41b815260009073b28c804e3dacff80701bbbafd106dbfb416a516890636c5d9cf0906124f590600d908990889060040161588c565b60206040518083038186803b15801561250d57600080fd5b505af4158015612521573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125459190615330565b600e54604051632e1a7d4d60e01b81529192506001600160a01b031690632e1a7d4d906125769084906004016158ab565b600060405180830381600087803b15801561259057600080fd5b505af11580156125a4573d6000803e3d6000fd5b5050600080525050600a602052600080516020615d2b833981519152546125ce90859083906138c8565b50612668565b6040516306c5d9cf60e41b8152612668908590859073b28c804e3dacff80701bbbafd106dbfb416a516890636c5d9cf09061261890600d9086908a9060040161588c565b60206040518083038186803b15801561263057600080fd5b505af4158015612644573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b59190615330565b50505050565b60405163014ef18960e11b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063029de31290610eec90849086906004016158b4565b60025490565b6011546001146126d25760405162461bcd60e51b815260040161084b906156f7565b60006011556040517f892cd8f5b436bd5fb7dac1f11aafb73345d892ba3e9fe09cd94d95ba84928e73906127099033908490615541565b60405180910390a160005a3360009081526010602052604081205491925090819060ff168061276257506000805260106020527f6e0956cda88cad152e89927e53611735b61a5c762d1428573c6931b0a5efcb015460ff165b905060005b848110156128e0576002546001016000908152600b602052604090205460ff16156127f9576040516305d4bd1160e01b8152736336788a85f54d8856782d58c1ca63c7d3844531906305d4bd11906127c4906000906004016158ab565b60006040518083038186803b1580156127dc57600080fd5b505af41580156127f0573d6000803e3d6000fd5b505050506128d8565b600080612806600061395a565b9092509050600082600481111561281957fe5b14806128255750428110155b156128315750506128e0565b838061284157506104b081014210155b61285d5760405162461bcd60e51b815260040161084b9061578d565b600194508482600481111561286e57fe5b14156128815761287c61397e565b6128d5565b600282600481111561288f57fe5b141561289d5761287c613c36565b60038260048111156128ab57fe5b14156128b95761287c613eaf565b60048260048111156128c757fe5b14156128d5576128d5614128565b50505b600101612767565b50811561295c57736336788a85f54d8856782d58c1ca63c7d3844531639db74df1600061290e5a8790612ddb565b6040518363ffffffff1660e01b815260040161292b929190615ab8565b60006040518083038186803b15801561294357600080fd5b505af4158015612957573d6000803e3d6000fd5b505050505b505060016011555050565b60065490565b60019190910180546001600160a01b0319166001600160a01b03909216919091179055565b6000806000806000806000736336788a85f54d8856782d58c1ca63c7d3844531634e1eb86090918a6040518363ffffffff1660e01b81526004016129d7929190615ac6565b60606040518083038186803b1580156129ef57600080fd5b505af4158015612a03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a279190614d5f565b92509250925060008088612a3c578383612a3f565b82845b9598509650939450505050509250925092565b60606000846001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b158015612a8f57600080fd5b505afa158015612aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ac79190614d43565b6001600160a01b0316638c09166e85856040518363ffffffff1660e01b8152600401612af4929190615ac6565b60206040518083038186803b158015612b0c57600080fd5b505afa158015612b20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b449190615330565b905080604051602001612b5791906158ab565b6040516020818303038152906040529150509392505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b60208310612bec5780518252601f199092019160209182019101612bcd565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612c4e576040519150601f19603f3d011682016040523d82523d6000602084013e612c53565b606091505b5091509150818015612c81575080511580612c815750808060200190516020811015612c7e57600080fd5b50515b610e0e576040805162461bcd60e51b815260206004808301919091526024820152635448303560e01b604482015290519081900360640190fd5b600e54604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d90612ceb9084906004016158ab565b600060405180830381600087803b158015612d0557600080fd5b505af1158015612d19573d6000803e3d6000fd5b50506000808052600a602052600080516020615d2b833981519152546040519193506001600160a01b0386169250908490612d539061552a565b600060405180830381858888f193505050503d8060008114612d91576040519150601f19603f3d011682016040523d82523d6000602084013e612d96565b606091505b50509050806123455760405163032b310f60e51b815273b28c804e3dacff80701bbbafd106dbfb416a51689063656621e090611d2690600d908790879060040161588c565b6000612e0483836040518060400160405280600481526020016329a6989960e11b815250614293565b9392505050565b80820182811015612e4c576040805162461bcd60e51b81526020600480830191909152602482015263534d344560e01b604482015290519081900360640190fd5b92915050565b6000846004811115612e6057fe5b1415612e7e5760405162461bcd60e51b815260040161084b9061585f565b600042612e8f856301e13380612e0b565b1090506001856004811115612ea057fe5b14156130785760405163117d7ab160e01b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063117d7ab190612ee29084908890600401615ab8565b6101a06040518083038186803b158015612efb57600080fd5b505af4158015612f0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f339190615119565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091612f7591859190600401615ac6565b60606040518083038186803b158015612f8d57600080fd5b505af4158015612fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc59190614d5f565b9250925050600084612fdb578360e00151612fe8565b600f546001600160a01b03165b9050613004818486602001518588604001518960a0015161432b565b6130205760405162461bcd60e51b815260040161084b90615733565b851561306f57600061304585610120015186610100015161449190919063ffffffff16565b905061305182826144e6565b61306d5760405162461bcd60e51b815260040161084b906157c9565b505b505050506135dd565b600285600481111561308657fe5b141561324a57604051634ce4436960e11b8152600090736336788a85f54d8856782d58c1ca63c7d3844531906399c886d2906130c89084908890600401615ab8565b6101206040518083038186803b1580156130e157600080fd5b505af41580156130f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613119919061527b565b8051604051630270f5c360e51b8152919250600091736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613158918591600401615ac6565b60606040518083038186803b15801561317057600080fd5b505af4158015613184573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a89190614d5f565b505090506000836131bd578260a001516131ca565b600f546001600160a01b03165b90506131db82828560200151614567565b6131f75760405162461bcd60e51b815260040161084b90615733565b841561324257600061321a8460e001518560c0015161449190919063ffffffff16565b905061322682826144e6565b61306f5760405162461bcd60e51b815260040161084b906157c9565b5050506135dd565b600385600481111561325857fe5b14156134055760405163ac1ecdb360e01b8152600090736336788a85f54d8856782d58c1ca63c7d38445319063ac1ecdb39061329a9084908890600401615ab8565b6101606040518083038186803b1580156132b357600080fd5b505af41580156132c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132eb9190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb8609161332d91859190600401615ac6565b60606040518083038186803b15801561334557600080fd5b505af4158015613359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337d9190614d5f565b9250925050600084613393578360a001516133a0565b600f546001600160a01b03165b90506133c684602001516133b457836133b6565b825b8286604001518760800151614676565b6133e25760405162461bcd60e51b815260040161084b90615733565b851561306f5760006130458560e001518660c0015161449190919063ffffffff16565b600485600481111561341357fe5b14156135dd576040516311c8197f60e01b8152600090736336788a85f54d8856782d58c1ca63c7d3844531906311c8197f906134559084908890600401615ab8565b6101606040518083038186803b15801561346e57600080fd5b505af4158015613482573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134a69190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb860916134e891859190600401615ac6565b60606040518083038186803b15801561350057600080fd5b505af4158015613514573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135389190614d5f565b925092505060008461354e578360a0015161355b565b600f546001600160a01b03165b905061356f84602001516133b457836133b6565b61358b5760405162461bcd60e51b815260040161084b90615733565b85156135d85760006135ae8560e001518660c0015161449190919063ffffffff16565b90506135ba82826144e6565b6135d65760405162461bcd60e51b815260040161084b906157c9565b505b505050505b610e0e600084614795565b8051604051630270f5c360e51b81526000918291829182918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb8609161362d91859190600401615ac6565b60606040518083038186803b15801561364557600080fd5b505af4158015613659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367d9190614d5f565b60208901516040516306c5d9cf60e41b8152939850919650945060009173b28c804e3dacff80701bbbafd106dbfb416a516891636c5d9cf0916136c891600d918a919060040161588c565b60206040518083038186803b1580156136e057600080fd5b505af41580156136f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137189190615330565b60408089015190516306c5d9cf60e41b815291925060009173b28c804e3dacff80701bbbafd106dbfb416a516891636c5d9cf09161375e91600d918a919060040161588c565b60206040518083038186803b15801561377657600080fd5b505af415801561378a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137ae9190615330565b9050866001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156137eb57600080fd5b505af11580156137ff573d6000803e3d6000fd5b5050505060e0880151604051633d2945e960e11b815273b291730099d3ac9975abd4003ba3bd47401fd2fd91637a528bd291613847918b918b908b9089908990600401615595565b604080518083038186803b15801561385e57600080fd5b505af4158015613872573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138969190615348565b9799969850949694959350505050565b81156138b7576138b7848684612b70565b8015610e0e57610e0e838683612b70565b6040516000906001600160a01b038516908390859084818181858888f193505050503d8060008114613916576040519150601f19603f3d011682016040523d82523d6000602084013e61391b565b606091505b5050905080612668576040805162461bcd60e51b815260206004808301919091526024820152632a2419a360e11b604482015290519081900360640190fd5b60008061396e8384600201546001016147c8565b90925063ffffffff169050915091565b60005a60405163a81df10f60e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d38445319063a81df10f906139be9084906004016158ab565b6101a06040518083038186803b1580156139d757600080fd5b505af41580156139eb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a0f9190615119565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613a5191859190600401615ac6565b60606040518083038186803b158015613a6957600080fd5b505af4158015613a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613aa19190614d5f565b6001600160a01b038082166000908152600a602052604080822054928516825281205493965091945090925082913091613af491613ae891906117af9062012c6c90612e0b565b61012088015190612ddb565b604051634ed4967d60e11b90613b0e908990602401615ada565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613b4c919061550e565b60006040518083038160008787f1925050503d8060008114613b8a576040519150601f19603f3d011682016040523d82523d6000602084013e613b8f565b606091505b509092509050600182613bbd57613bba8660e00151868860200151878a604001518b60a0015161432b565b90505b613bc6816147fe565b600080613be38861012001518961010001518b8b60e0015161481f565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613c239392919061569d565b60405180910390a3505050505050505050565b60005a6040516313ed2f6160e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d3844531906313ed2f6190613c769084906004016158ab565b6101206040518083038186803b158015613c8f57600080fd5b505af4158015613ca3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cc7919061527b565b905060008030613cea613cdf62012c6c61d6d8612e0b565b60e086015190612ddb565b604051631a42443160e21b90613d04908790602401615ba0565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613d42919061550e565b60006040518083038160008787f1925050503d8060008114613d80576040519150601f19603f3d011682016040523d82523d6000602084013e613d85565b606091505b509092509050600182613e3a578351604051630270f5c360e51b8152600091736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613dcf91859190600401615ac6565b60606040518083038186803b158015613de757600080fd5b505af4158015613dfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e1f9190614d5f565b50509050613e36818660a001518760200151614567565b9150505b613e43816147fe565b600080613e5e8660e001518760c00151898960a0015161481f565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613e9e9392919061569d565b60405180910390a350505050505050565b60005a604051632e9d30e160e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d384453190632e9d30e190613eef9084906004016158ab565b6101606040518083038186803b158015613f0857600080fd5b505af4158015613f1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f409190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb86091613f8291859190600401615ac6565b60606040518083038186803b158015613f9a57600080fd5b505af4158015613fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fd29190614d5f565b9250925050600080306001600160a01b03166140316140266000600a01600089602001516140005788614002565b875b6001600160a01b0316815260208101919091526040016000205462012c6c90612e0b565b60e088015190612ddb565b604051630b65604d60e01b9061404b90899060240161587d565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614089919061550e565b60006040518083038160008787f1925050503d80600081146140c7576040519150601f19603f3d011682016040523d82523d6000602084013e6140cc565b606091505b5090925090506001826141045761410186602001516140eb57856140ed565b845b8760a0015188604001518960800151614676565b90505b61410d816147fe565b600080613be38860e001518960c001518b8b60a0015161481f565b60005a60405163a1ba139560e01b8152909150600090736336788a85f54d8856782d58c1ca63c7d38445319063a1ba1395906141689084906004016158ab565b6101606040518083038186803b15801561418157600080fd5b505af4158015614195573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141b99190615011565b8051604051630270f5c360e51b81529192506000918291736336788a85f54d8856782d58c1ca63c7d384453191634e1eb860916141fb91859190600401615ac6565b60606040518083038186803b15801561421357600080fd5b505af4158015614227573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061424b9190614d5f565b9250925050600080306001600160a01b03166142796140266000600a01600089602001516140005788614002565b604051633c763c1760e01b9061404b90899060240161587d565b81830381848211156143235760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156142e85781810151838201526020016142d0565b50505050905090810190601f1680156143155780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509392505050565b6001600160a01b038381166000908152600a6020526040808220549288168252812054909182918291309161435f91612e0b565b604051633ed76f1760e01b90614383908d908d908d908d908d908d906024016155cf565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516143c1919061550e565b60006040518083038160008787f1925050503d80600081146143ff576040519150601f19603f3d011682016040523d82523d6000602084013e614404565b606091505b50915091508161448557876001600160a01b0316896001600160a01b0316600080516020615d0b8339815191528984604051614441929190615c17565b60405180910390a3856001600160a01b0316896001600160a01b0316600080516020615d0b833981519152878460405161447c929190615c17565b60405180910390a35b50979650505050505050565b60008115806144ac575050808202828282816144a957fe5b04145b612e4c576040805162461bcd60e51b81526020600480830191909152602482015263534d324160e01b604482015290519081900360640190fd5b6000816144f557506001612e4c565b60008052600a602052600080516020615d2b8339815191525461451b90849084906148af565b9050801515836001600160a01b03167fdbef2fc26e7694e7a1c5a4801b1ad144136d149cf76f310a780689b4087f0ffe8460405161455991906158ab565b60405180910390a392915050565b60008161457657506001612e04565b600080306001600160a01b031661d6d863c9cd976060e01b88888860006040516024016145a69493929190615609565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516145e4919061550e565b60006040518083038160008787f1925050503d8060008114614622576040519150601f19603f3d011682016040523d82523d6000602084013e614627565b606091505b50915091508161466d57856001600160a01b0316856001600160a01b0316600080516020615d0b8339815191528684604051614664929190615c17565b60405180910390a35b50949350505050565b6000826146855750600161478d565b6001600160a01b0385166000908152600a60205260408082205490518291309163e5b1be6560e01b906146c2908b908b908b908b90602401615609565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614700919061550e565b60006040518083038160008787f1925050503d806000811461473e576040519150601f19603f3d011682016040523d82523d6000602084013e614743565b606091505b50915091508161478957866001600160a01b0316866001600160a01b0316600080516020615d0b8339815191528784604051614780929190615c17565b60405180910390a35b5090505b949350505050565b6000908152600391820160205260408120818155600181018290556002810180546001600160e81b031916905590910155565b60008181526003830160205260408120805463ffffffff610100820416919060ff166147f38161490d565b935050509250929050565b806148125761480d600061497d565b61481c565b61481c60006149d0565b50565b6000808061482d8787614491565b90506148406155946117af5a8890612ddb565b92506000614865826148606000600601548761449190919063ffffffff16565b614a07565b90506148718282612ddb565b925061487d33826144e6565b6148995760405162461bcd60e51b815260040161084b906157c9565b6148a385846144e6565b50505094509492505050565b6040516000906001600160a01b038516908390859084818181858888f193505050503d80600081146148fd576040519150601f19603f3d011682016040523d82523d6000602084013e614902565b606091505b509095945050505050565b6000600182141561492057506001610eab565b600282141561493157506002610eab565b600382141561494257506004610eab565b600482141561495357506004610eab565b600582141561496457506003610eab565b600682141561497557506003610eab565b506000919050565b600281015460009081526003820160205260409020805465010000000000900460ff16156149ac5760036149af565b60025b815460ff91909116650100000000000265ff00000000001990911617905550565b60028082015460009081526003928301602052604081208181556001810182905591820180546001600160e81b0319169055910155565b6000818310614a165781612e04565b5090919050565b604051806101200160405280600063ffffffff16815260200160008152602001600081526020016000815260200160001515815260200160006001600160a01b031681526020016000815260200160008152602001600063ffffffff1681525090565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b604051806101a00160405280600063ffffffff1681526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160006001600160a01b031681526020016000815260200160008152602001600063ffffffff16815260200160008152602001600063ffffffff1681525090565b8035610eab81615cc8565b8051610eab81615cc8565b8035610eab81615cdd565b8051610eab81615cdd565b6000610160808385031215614ba2578182fd5b614bab81615c78565b915050614bb782614d11565b8152614bc560208301614b79565b60208201526040820135604082015260608201356060820152614bea60808301614b79565b6080820152614bfb60a08301614b63565b60a082015260c082013560c082015260e082013560e0820152610100614c22818401614d11565b908201526101208281013590820152610140614c3f818401614d11565b9082015292915050565b6000610160808385031215614c5c578182fd5b614c6581615c78565b915050614c7182614d1c565b8152614c7f60208301614b84565b60208201526040820151604082015260608201516060820152614ca460808301614b84565b6080820152614cb560a08301614b6e565b60a082015260c082015160c082015260e082015160e0820152610100614cdc818401614d1c565b908201526101208281015190820152610140614c3f818401614d1c565b60006101008284031215614d0b578081fd5b50919050565b8035610eab81615cf8565b8051610eab81615cf8565b600060208284031215614d38578081fd5b8135612e0481615cc8565b600060208284031215614d54578081fd5b8151612e0481615cc8565b600080600060608486031215614d73578182fd5b8351614d7e81615cc8565b6020850151909350614d8f81615cc8565b6040850151909250614da081615cc8565b809150509250925092565b600080600060608486031215614dbf578081fd5b8335614dca81615cc8565b92506020840135614dda81615cc8565b929592945050506040919091013590565b60008060008060008060c08789031215614e03578384fd5b8635614e0e81615cc8565b95506020870135614e1e81615cc8565b9450604087013593506060870135614e3581615cc8565b92506080870135915060a0870135614e4c81615cdd565b809150509295509295509295565b60008060008060808587031215614e6f578182fd5b8435614e7a81615cc8565b93506020850135614e8a81615cc8565b9250604085013591506060850135614ea181615cdd565b939692955090935050565b60008060408385031215614ebe578182fd5b8235614ec981615cc8565b91506020830135614ed981615cdd565b809150509250929050565b600080600060608486031215614ef8578081fd5b8335614f0381615cc8565b92506020840135614f1381615ceb565b91506040840135614da081615cdd565b60008060408385031215614f35578182fd5b8235614f4081615cc8565b946020939093013593505050565b600060208284031215614f5f578081fd5b8151612e0481615cdd565b60008060008060808587031215614f7f578182fd5b8451614f8a81615cdd565b60208601516040870151606090970151919890975090945092505050565b600060208284031215614fb9578081fd5b815160068110612e04578182fd5b60008060408385031215614fd9578182fd5b8251614fe481615ceb565b6020840151909250614ed981615cf8565b60006101608284031215615007578081fd5b612e048383614b8f565b60006101608284031215615023578081fd5b612e048383614c49565b6000610100828403121561503f578081fd5b612e048383614cf9565b60006101a080838503121561505c578182fd5b61506581615c78565b905061507083614d11565b8152602083013560208201526040830135604082015260608301356060820152608083013560808201526150a660a08401614b79565b60a08201526150b760c08401614b79565b60c08201526150c860e08401614b63565b60e0820152610100838101359082015261012080840135908201526101406150f1818501614d11565b90820152610160838101359082015261018061510e818501614d11565b908201529392505050565b60006101a080838503121561512c578182fd5b61513581615c78565b905061514083614d1c565b81526020830151602082015260408301516040820152606083015160608201526080830151608082015261517660a08401614b84565b60a082015261518760c08401614b84565b60c082015261519860e08401614b6e565b60e0820152610100838101519082015261012080840151908201526101406151c1818501614d1c565b90820152610160838101519082015261018061510e818501614d1c565b60006101608284031215614d0b578081fd5b6000610120808385031215615203578182fd5b61520c81615c78565b905061521783614d11565b815260208301356020820152604083013560408201526060830135606082015261524360808401614b79565b608082015261525460a08401614b63565b60a082015260c083013560c082015260e083013560e082015261010061510e818501614d11565b600061012080838503121561528e578182fd5b61529781615c78565b90506152a283614d1c565b81526020830151602082015260408301516040820152606083015160608201526152ce60808401614b84565b60808201526152df60a08401614b6e565b60a082015260c083015160c082015260e083015160e082015261010061510e818501614d1c565b60006101208284031215614d0b578081fd5b600060208284031215615329578081fd5b5035919050565b600060208284031215615341578081fd5b5051919050565b6000806040838503121561535a578182fd5b505080516020909101519092909150565b60006020828403121561537c578081fd5b8135612e0481615cf8565b6001600160a01b03169052565b15159052565b600081518084526153b2816020860160208601615c9c565b601f01601f19169290920160200192915050565b600581106153d057fe5b9052565b6153df828251615504565b60208101516153f16020840182615394565b50604081015160408301526060810151606083015260808101516154186080840182615394565b5060a081015161542b60a0840182615387565b5060c081015160c083015260e081015160e08301526101008082015161545382850182615504565b505061012081810151908301526101408082015161266882850182615504565b803561547e81615cc8565b6001600160a01b03908116835260208201359061549a82615cc8565b166020830152604081810135908301526060808201359083015260808101356154c281615cdd565b1515608083015260a08101356154d781615cc8565b6154e460a0840182615387565b5060c081013560c08301526154fb60e08201614d11565b61234560e08401825b63ffffffff169052565b60008251615520818460208701615c9c565b9190910192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039687168152948616602086015292851660408501529084166060840152909216608082015260a081019190915260c00190565b6001600160a01b0396871681529486166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b6001600160a01b0396871681529486166020860152604085019390935293166060830152608082019290925290151560a082015260c00190565b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061566c9083018461539a565b979650505050505050565b6001600160a01b039290921682521515602082015260400190565b901515815260200190565b6000606082526156b0606083018661539a565b60208301949094525060400152919050565b60208101600683106156d057fe5b91905290565b604081016156e482856153c6565b63ffffffff831660208301529392505050565b6020808252600490820152632a22181b60e11b604082015260600190565b6020808252600490820152635444314360e01b604082015260600190565b60208082526004908201526315110c4d60e21b604082015260600190565b6020808252600490820152635444303360e01b604082015260600190565b6020808252600490820152635444333760e01b604082015260600190565b6020808252600490820152630544430360e41b604082015260600190565b6020808252600490820152635444303160e01b604082015260600190565b6020808252600490820152630544434360e41b604082015260600190565b60208082526004908201526315110c0d60e21b604082015260600190565b6020808252600490820152632a221a9960e11b604082015260600190565b6020808252600490820152632a22181960e11b604082015260600190565b6020808252600490820152630a88860760e31b604082015260600190565b6020808252600490820152635444343160e01b604082015260600190565b6101608101612e4c82846153d4565b9283526001600160a01b03919091166020830152604082015260600190565b90815260200190565b9182526001600160a01b0316602082015260400190565b8481526001600160a01b0384166020820152608081016158ee60408301856153c6565b821515606083015295945050505050565b83815261014081016159146020830185615473565b82610120830152949350505050565b8381526101a081016159406020830161593b86614b63565b615387565b61594c60208501614b63565b6159596040840182615387565b506040840135606083015260608401356080830152608084013560a083015260a084013560c083015261598e60c08501614b79565b61599b60e0840182615394565b506159a860e08501614b79565b6101006159b781850183615394565b6159c2818701614b63565b9150506101206159d481850183615387565b61014091508086013582850152506159ed818601614d11565b90506159fd610160840182615504565b5082610180830152949350505050565b8281526101408101615a256020830161593b85614b63565b615a3160208401614b63565b615a3e6040840182615387565b506040830135606083015260608301356080830152608083013560a0830152615a6960a08401614b79565b615a7660c0840182615394565b50615a8360c08401614b63565b615a9060e0840182615387565b5061010060e084013581840152615aa8818501614d11565b9050614323610120840182615504565b918252602082015260400190565b91825263ffffffff16602082015260400190565b60006101a082019050615aee828451615504565b6020830151602083015260408301516040830152606083015160608301526080830151608083015260a0830151615b2860a0840182615394565b5060c0830151615b3b60c0840182615394565b5060e0830151615b4e60e0840182615387565b506101008381015190830152610120808401519083015261014080840151615b7882850182615504565b5050610160838101519083015261018080840151615b9882850182615504565b505092915050565b60006101208201905063ffffffff835116825260208301516020830152604083015160408301526060830151606083015260808301511515608083015260a0830151615bef60a0840182615387565b5060c083015160c083015260e083015160e083015261010080840151615b9882850182615504565b60008382526040602083015261478d604083018461539a565b600085825284602083015260018060a01b038416604083015260806060830152615c5d608083018461539a565b9695505050505050565b63ffffffff91909116815260200190565b60405181810167ffffffffffffffff81118282101715615c9457fe5b604052919050565b60005b83811015615cb7578181015183820152602001615c9f565b838111156126685750506000910152565b6001600160a01b038116811461481c57600080fd5b801515811461481c57600080fd5b6005811061481c57600080fd5b63ffffffff8116811461481c57600080fdfe786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b21159213da86008ba1c6922daee3e07db95305ef49ebced9f5467a0b8613fcc6b343e3a26469706673582212204869fe8a86a81d32e462924c6375438fb998a95decb6fe160a341c323c1eee6f64736f6c63430007060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c6000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000003a1d749fa4a9e650fce844ff1c58c5faf7e2a9d1
-----Decoded View---------------
Arg [0] : _factory (address): 0xC480b33eE5229DE3FbDFAD1D2DCD3F3BAD0C56c6
Arg [1] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [2] : _bot (address): 0x3a1D749fa4a9E650FCe844fF1C58C5faf7e2a9D1
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c6
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [2] : 0000000000000000000000003a1d749fa4a9e650fce844ff1c58c5faf7e2a9d1
Loading...
Loading
Loading...
Loading
OVERVIEW
The Delay contract of Integral SIZE.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.