More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 3,669 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Sell | 18473556 | 392 days ago | IN | 0.01031758 ETH | 0.00166611 | ||||
Set Order Disabl... | 18469036 | 393 days ago | IN | 0 ETH | 0.00058528 | ||||
Set Order Disabl... | 18469036 | 393 days ago | IN | 0 ETH | 0.00058528 | ||||
Set Order Disabl... | 18469035 | 393 days ago | IN | 0 ETH | 0.00058151 | ||||
Set Order Disabl... | 18469035 | 393 days ago | IN | 0 ETH | 0.00086275 | ||||
Set Order Disabl... | 18469034 | 393 days ago | IN | 0 ETH | 0.00061492 | ||||
Set Order Disabl... | 18469033 | 393 days ago | IN | 0 ETH | 0.0006233 | ||||
Set Order Disabl... | 18469033 | 393 days ago | IN | 0 ETH | 0.0006233 | ||||
Set Order Disabl... | 18469033 | 393 days ago | IN | 0 ETH | 0.00092475 | ||||
Set Order Disabl... | 18469032 | 393 days ago | IN | 0 ETH | 0.00060428 | ||||
Set Order Disabl... | 18469031 | 393 days ago | IN | 0 ETH | 0.00059383 | ||||
Set Order Disabl... | 18469031 | 393 days ago | IN | 0 ETH | 0.00059383 | ||||
Set Order Disabl... | 18469031 | 393 days ago | IN | 0 ETH | 0.00088103 | ||||
Set Order Disabl... | 18469030 | 393 days ago | IN | 0 ETH | 0.00063498 | ||||
Set Order Disabl... | 18469029 | 393 days ago | IN | 0 ETH | 0.00060673 | ||||
Set Order Disabl... | 18469029 | 393 days ago | IN | 0 ETH | 0.00060673 | ||||
Set Order Disabl... | 18469029 | 393 days ago | IN | 0 ETH | 0.00090018 | ||||
Set Order Disabl... | 18469028 | 393 days ago | IN | 0 ETH | 0.00061077 | ||||
Set Order Disabl... | 18469028 | 393 days ago | IN | 0 ETH | 0.00061077 | ||||
Set Order Disabl... | 18469027 | 393 days ago | IN | 0 ETH | 0.00061969 | ||||
Set Order Disabl... | 18469027 | 393 days ago | IN | 0 ETH | 0.0009194 | ||||
Set Order Disabl... | 18469025 | 393 days ago | IN | 0 ETH | 0.00060919 | ||||
Set Order Disabl... | 18469025 | 393 days ago | IN | 0 ETH | 0.00060919 | ||||
Set Order Disabl... | 18469024 | 393 days ago | IN | 0 ETH | 0.00057494 | ||||
Set Order Disabl... | 18469024 | 393 days ago | IN | 0 ETH | 0.00085301 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
18468760 | 393 days ago | 0.00557921 ETH | ||||
18468760 | 393 days ago | 0.00481671 ETH | ||||
18468719 | 393 days ago | 0.00509102 ETH | ||||
18468719 | 393 days ago | 0.0053049 ETH | ||||
18468638 | 393 days ago | 0.00538257 ETH | ||||
18468638 | 393 days ago | 0.00501335 ETH | ||||
18468617 | 393 days ago | 0.00546029 ETH | ||||
18468617 | 393 days ago | 0.00493563 ETH | ||||
18468609 | 393 days ago | 0.01039592 ETH | ||||
18468566 | 393 days ago | 0.01039592 ETH | ||||
18468486 | 393 days ago | 0.01039592 ETH | ||||
18468465 | 393 days ago | 0.01039592 ETH | ||||
18468384 | 393 days ago | 0.00494707 ETH | ||||
18468384 | 393 days ago | 0.00543921 ETH | ||||
18468232 | 393 days ago | 0.01038628 ETH | ||||
18468063 | 393 days ago | 0.00514155 ETH | ||||
18468063 | 393 days ago | 0.00514304 ETH | ||||
18468058 | 393 days ago | 0.00527319 ETH | ||||
18468058 | 393 days ago | 0.0050114 ETH | ||||
18467932 | 393 days ago | 0.00514101 ETH | ||||
18467932 | 393 days ago | 0.00517921 ETH | ||||
18467917 | 393 days ago | 0.00522417 ETH | ||||
18467917 | 393 days ago | 0.00513832 ETH | ||||
18467911 | 393 days ago | 0.01028459 ETH | ||||
18467905 | 393 days ago | 0.01028459 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
TwapDelay
Compiler Version
v0.7.6+commit.7338295f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; pragma abicoder v2; import './interfaces/ITwapPair.sol'; import './interfaces/ITwapDelay.sol'; import './interfaces/IWETH.sol'; import './libraries/SafeMath.sol'; import './libraries/Orders.sol'; import './libraries/TokenShares.sol'; import './libraries/AddLiquidity.sol'; import './libraries/WithdrawHelper.sol'; contract TwapDelay is ITwapDelay { using SafeMath for uint256; using Orders for Orders.Data; using TokenShares for TokenShares.Data; Orders.Data internal orders; TokenShares.Data internal tokenShares; uint256 private constant ORDER_CANCEL_TIME = 24 hours; uint256 private constant BOT_EXECUTION_TIME = 20 minutes; uint256 private constant ORDER_LIFESPAN = 48 hours; uint16 private constant MAX_TOLERANCE = 10; address public override owner; address public override relayer; mapping(address => bool) public override isBot; mapping(address => uint16) public override tolerance; constructor( address _factory, address _weth, address _bot ) { orders.factory = _factory; owner = msg.sender; isBot[_bot] = true; orders.gasPrice = tx.gasprice; tokenShares.weth = _weth; orders.delay = 30 minutes; orders.maxGasLimit = 5_000_000; orders.gasPriceInertia = 20_000_000; orders.maxGasPriceImpact = 1_000_000; orders.setTransferGasCost(address(0), Orders.ETHER_TRANSFER_CALL_COST); emit OwnerSet(msg.sender); } function getTransferGasCost(address token) external view override returns (uint256 gasCost) { return orders.transferGasCosts[token]; } function getDepositDisabled(address pair) external view override returns (bool) { return orders.getDepositDisabled(pair); } function getWithdrawDisabled(address pair) external view override returns (bool) { return orders.getWithdrawDisabled(pair); } function getBuyDisabled(address pair) external view override returns (bool) { return orders.getBuyDisabled(pair); } function getSellDisabled(address pair) external view override returns (bool) { return orders.getSellDisabled(pair); } function getOrderStatus(uint256 orderId, uint256 validAfterTimestamp) external view override returns (Orders.OrderStatus) { return orders.getOrderStatus(orderId, validAfterTimestamp); } uint256 private locked; modifier lock() { require(locked == 0, 'TD06'); locked = 1; _; locked = 0; } function factory() external view override returns (address) { return orders.factory; } function totalShares(address token) external view override returns (uint256) { return tokenShares.totalShares[token]; } // returns wrapped native currency for particular blockchain (WETH or WMATIC) function weth() external view override returns (address) { return tokenShares.weth; } function isNonRebasingToken(address token) external view override returns (bool) { return tokenShares.nonRebasingToken[token]; } function delay() external view override returns (uint256) { return orders.delay; } function lastProcessedOrderId() external view returns (uint256) { return orders.lastProcessedOrderId; } function newestOrderId() external view returns (uint256) { return orders.newestOrderId; } function isOrderCanceled(uint256 orderId) external view returns (bool) { return orders.canceled[orderId]; } function maxGasLimit() external view override returns (uint256) { return orders.maxGasLimit; } function maxGasPriceImpact() external view override returns (uint256) { return orders.maxGasPriceImpact; } function gasPriceInertia() external view override returns (uint256) { return orders.gasPriceInertia; } function gasPrice() external view override returns (uint256) { return orders.gasPrice; } function setOrderDisabled( address pair, Orders.OrderType orderType, bool disabled ) external payable override { require(msg.sender == owner, 'TD00'); orders.setOrderDisabled(pair, orderType, disabled); } function setOwner(address _owner) external payable override { require(msg.sender == owner, 'TD00'); // require(_owner != owner, 'TD01'); // Comment out to save size require(_owner != address(0), 'TD02'); owner = _owner; emit OwnerSet(_owner); } function setBot(address _bot, bool _isBot) external payable override { require(msg.sender == owner, 'TD00'); // require(_isBot != isBot[_bot], 'TD01'); // Comment out to save size isBot[_bot] = _isBot; emit BotSet(_bot, _isBot); } function setMaxGasLimit(uint256 _maxGasLimit) external payable override { require(msg.sender == owner, 'TD00'); orders.setMaxGasLimit(_maxGasLimit); } function setDelay(uint32 _delay) external payable override { require(msg.sender == owner, 'TD00'); // require(_delay != orders.delay, 'TD01'); // Comment out to save size orders.delay = _delay; emit DelaySet(_delay); } function setRelayer(address _relayer) external payable override { require(msg.sender == owner, 'TD00'); require(_relayer != relayer, 'TD01'); require(_relayer != address(0), 'TD02'); relayer = _relayer; emit RelayerSet(_relayer); } function setGasPriceInertia(uint256 _gasPriceInertia) external payable override { require(msg.sender == owner, 'TD00'); orders.setGasPriceInertia(_gasPriceInertia); } function setMaxGasPriceImpact(uint256 _maxGasPriceImpact) external payable override { require(msg.sender == owner, 'TD00'); orders.setMaxGasPriceImpact(_maxGasPriceImpact); } function setTransferGasCost(address token, uint256 gasCost) external payable override { require(msg.sender == owner, 'TD00'); orders.setTransferGasCost(token, gasCost); } function setTolerance(address pair, uint16 amount) external payable override { require(msg.sender == owner, 'TD00'); require(amount <= MAX_TOLERANCE, 'TD54'); tolerance[pair] = amount; emit ToleranceSet(pair, amount); } function setNonRebasingToken(address token, bool isNonRebasing) external payable override { require(msg.sender == owner, 'TD00'); require(tokenShares.totalShares[token] == 0, 'TD74'); require(isNonRebasing != tokenShares.nonRebasingToken[token], 'TD01'); tokenShares.nonRebasingToken[token] = isNonRebasing; emit NonRebasingTokenSet(token, isNonRebasing); } function deposit(Orders.DepositParams calldata depositParams) external payable override lock returns (uint256 orderId) { orders.deposit(depositParams, tokenShares); return orders.newestOrderId; } function withdraw(Orders.WithdrawParams calldata withdrawParams) external payable override lock returns (uint256 orderId) { orders.withdraw(withdrawParams); return orders.newestOrderId; } function sell(Orders.SellParams calldata sellParams) external payable override lock returns (uint256 orderId) { orders.sell(sellParams, tokenShares); return orders.newestOrderId; } function relayerSell(Orders.SellParams calldata sellParams) external payable override lock returns (uint256 orderId) { require(msg.sender == relayer, 'TD00'); orders.relayerSell(sellParams, tokenShares); return orders.newestOrderId; } function buy(Orders.BuyParams calldata buyParams) external payable override lock returns (uint256 orderId) { orders.buy(buyParams, tokenShares); return orders.newestOrderId; } /// @dev This implementation processes orders sequentially and skips orders that have already been executed. /// If it encounters an order that is not yet valid, it stops execution since subsequent orders will also be invalid /// at the time. function execute(Orders.Order[] calldata _orders) external payable override lock { uint256 ordersLength = _orders.length; uint256 gasBefore = gasleft(); bool orderExecuted; bool senderCanExecute = isBot[msg.sender] || isBot[address(0)]; for (uint256 i; i < ordersLength; ++i) { if (_orders[i].orderId <= orders.lastProcessedOrderId) { continue; } if (orders.canceled[_orders[i].orderId]) { orders.dequeueOrder(_orders[i].orderId); continue; } orders.verifyOrder(_orders[i]); uint256 validAfterTimestamp = _orders[i].validAfterTimestamp; if (validAfterTimestamp >= block.timestamp) { break; } require(senderCanExecute || block.timestamp >= validAfterTimestamp + BOT_EXECUTION_TIME, 'TD00'); orderExecuted = true; if (_orders[i].orderType == Orders.DEPOSIT_TYPE) { executeDeposit(_orders[i]); } else if (_orders[i].orderType == Orders.WITHDRAW_TYPE) { executeWithdraw(_orders[i]); } else if (_orders[i].orderType == Orders.SELL_TYPE || _orders[i].orderType == Orders.SELL_INVERTED_TYPE) { executeSell(_orders[i]); } else if (_orders[i].orderType == Orders.BUY_TYPE || _orders[i].orderType == Orders.BUY_INVERTED_TYPE) { executeBuy(_orders[i]); } } if (orderExecuted) { orders.updateGasPrice(gasBefore.sub(gasleft())); } } /// @dev The `order` must be verified by calling `Orders.verifyOrder` before calling this function. function executeDeposit(Orders.Order calldata order) internal { uint256 gasStart = gasleft(); orders.dequeueOrder(order.orderId); (bool executionSuccess, bytes memory data) = address(this).call{ gas: order.gasLimit.sub( Orders.ORDER_BASE_COST.add(orders.transferGasCosts[order.token0]).add( orders.transferGasCosts[order.token1] ) ) }(abi.encodeWithSelector(this._executeDeposit.selector, order)); bool refundSuccess = true; if (!executionSuccess) { refundSuccess = refundTokens( order.to, order.token0, order.value0, order.token1, order.value1, order.unwrap ); } finalizeOrder(refundSuccess); (uint256 gasUsed, uint256 ethRefund) = refund(order.gasLimit, order.gasPrice, gasStart, order.to); emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund); } /// @dev The `order` must be verified by calling `Orders.verifyOrder` before calling this function. function executeWithdraw(Orders.Order calldata order) internal { uint256 gasStart = gasleft(); orders.dequeueOrder(order.orderId); (bool executionSuccess, bytes memory data) = address(this).call{ gas: order.gasLimit.sub(Orders.ORDER_BASE_COST.add(Orders.PAIR_TRANSFER_COST)) }(abi.encodeWithSelector(this._executeWithdraw.selector, order)); bool refundSuccess = true; if (!executionSuccess) { (address pair, ) = orders.getPair(order.token0, order.token1); refundSuccess = Orders.refundLiquidity(pair, order.to, order.liquidity, this._refundLiquidity.selector); } finalizeOrder(refundSuccess); (uint256 gasUsed, uint256 ethRefund) = refund(order.gasLimit, order.gasPrice, gasStart, order.to); emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund); } /// @dev The `order` must be verified by calling `Orders.verifyOrder` before calling this function. function executeSell(Orders.Order calldata order) internal { uint256 gasStart = gasleft(); orders.dequeueOrder(order.orderId); (bool executionSuccess, bytes memory data) = address(this).call{ gas: order.gasLimit.sub(Orders.ORDER_BASE_COST.add(orders.transferGasCosts[order.token0])) }(abi.encodeWithSelector(this._executeSell.selector, order)); bool refundSuccess = true; if (!executionSuccess) { refundSuccess = refundToken(order.token0, order.to, order.value0, order.unwrap); } finalizeOrder(refundSuccess); (uint256 gasUsed, uint256 ethRefund) = refund(order.gasLimit, order.gasPrice, gasStart, order.to); emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund); } /// @dev The `order` must be verified by calling `Orders.verifyOrder` before calling this function. function executeBuy(Orders.Order calldata order) internal { uint256 gasStart = gasleft(); orders.dequeueOrder(order.orderId); (bool executionSuccess, bytes memory data) = address(this).call{ gas: order.gasLimit.sub(Orders.ORDER_BASE_COST.add(orders.transferGasCosts[order.token0])) }(abi.encodeWithSelector(this._executeBuy.selector, order)); bool refundSuccess = true; if (!executionSuccess) { refundSuccess = refundToken(order.token0, order.to, order.value0, order.unwrap); } finalizeOrder(refundSuccess); (uint256 gasUsed, uint256 ethRefund) = refund(order.gasLimit, order.gasPrice, gasStart, order.to); emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund); } function finalizeOrder(bool refundSuccess) private { if (!refundSuccess) { orders.markRefundFailed(); } else { orders.forgetLastProcessedOrder(); } } function refund( uint256 gasLimit, uint256 gasPriceInOrder, uint256 gasStart, address to ) private returns (uint256 gasUsed, uint256 leftOver) { uint256 feeCollected = gasLimit.mul(gasPriceInOrder); gasUsed = gasStart.sub(gasleft()).add(Orders.REFUND_BASE_COST); uint256 actualRefund = Math.min(feeCollected, gasUsed.mul(orders.gasPrice)); leftOver = feeCollected.sub(actualRefund); require(refundEth(msg.sender, actualRefund), 'TD40'); refundEth(payable(to), leftOver); } function refundEth(address payable to, uint256 value) internal returns (bool success) { if (value == 0) { return true; } success = TransferHelper.transferETH(to, value, orders.transferGasCosts[address(0)]); emit EthRefund(to, success, value); } function refundToken( address token, address to, uint256 share, bool unwrap ) private returns (bool) { if (share == 0) { return true; } (bool success, bytes memory data) = address(this).call{ gas: orders.transferGasCosts[token] }( abi.encodeWithSelector(this._refundToken.selector, token, to, share, unwrap) ); if (!success) { emit RefundFailed(to, token, share, data); } return success; } function refundTokens( address to, address token0, uint256 share0, address token1, uint256 share1, bool unwrap ) private returns (bool) { (bool success, bytes memory data) = address(this).call{ gas: orders.transferGasCosts[token0].add(orders.transferGasCosts[token1]) }(abi.encodeWithSelector(this._refundTokens.selector, to, token0, share0, token1, share1, unwrap)); if (!success) { emit RefundFailed(to, token0, share0, data); emit RefundFailed(to, token1, share1, data); } return success; } function _refundTokens( address to, address token0, uint256 share0, address token1, uint256 share1, bool unwrap ) external payable { // no need to check sender, because it is checked in _refundToken _refundToken(token0, to, share0, unwrap); _refundToken(token1, to, share1, unwrap); } function _refundToken( address token, address to, uint256 share, bool unwrap ) public payable { require(msg.sender == address(this), 'TD00'); if (token == tokenShares.weth && unwrap) { uint256 amount = tokenShares.sharesToAmount(token, share, 0, to); IWETH(tokenShares.weth).withdraw(amount); TransferHelper.safeTransferETH(to, amount, orders.transferGasCosts[address(0)]); } else { TransferHelper.safeTransfer(token, to, tokenShares.sharesToAmount(token, share, 0, to)); } } function _refundLiquidity( address pair, address to, uint256 liquidity ) external payable { require(msg.sender == address(this), 'TD00'); return TransferHelper.safeTransfer(pair, to, liquidity); } function _executeDeposit(Orders.Order calldata order) external payable { require(msg.sender == address(this), 'TD00'); require(order.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04'); (address pair, ) = orders.getPair(order.token0, order.token1); (uint256 amount0Left, uint256 amount1Left, uint256 swapToken) = _initialDeposit(order, pair); if (order.swap && swapToken != 0) { bytes memory data = encodePriceInfo(pair, order.priceAccumulator, order.timestamp); if (amount0Left != 0 && swapToken == 1) { uint256 extraAmount1; (amount0Left, extraAmount1) = AddLiquidity.swapDeposit0( pair, order.token0, amount0Left, order.minSwapPrice, tolerance[pair], data ); amount1Left = amount1Left.add(extraAmount1); } else if (amount1Left != 0 && swapToken == 2) { uint256 extraAmount0; (extraAmount0, amount1Left) = AddLiquidity.swapDeposit1( pair, order.token1, amount1Left, order.maxSwapPrice, tolerance[pair], data ); amount0Left = amount0Left.add(extraAmount0); } } if (amount0Left != 0 && amount1Left != 0) { (amount0Left, amount1Left, ) = AddLiquidity.addLiquidityAndMint( pair, order.to, order.token0, order.token1, amount0Left, amount1Left ); } AddLiquidity._refundDeposit(order.to, order.token0, order.token1, amount0Left, amount1Left); } function _initialDeposit(Orders.Order calldata order, address pair) private returns ( uint256 amount0Left, uint256 amount1Left, uint256 swapToken ) { uint256 amount0Desired = tokenShares.sharesToAmount(order.token0, order.value0, order.amountLimit0, order.to); uint256 amount1Desired = tokenShares.sharesToAmount(order.token1, order.value1, order.amountLimit1, order.to); ITwapPair(pair).sync(); (amount0Left, amount1Left, swapToken) = AddLiquidity.addLiquidityAndMint( pair, order.to, order.token0, order.token1, amount0Desired, amount1Desired ); } function _executeWithdraw(Orders.Order calldata order) external payable { require(msg.sender == address(this), 'TD00'); require(order.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04'); (address pair, ) = orders.getPair(order.token0, order.token1); ITwapPair(pair).sync(); TransferHelper.safeTransfer(pair, pair, order.liquidity); uint256 wethAmount; uint256 amount0; uint256 amount1; if (order.unwrap && (order.token0 == tokenShares.weth || order.token1 == tokenShares.weth)) { bool success; (success, wethAmount, amount0, amount1) = WithdrawHelper.withdrawAndUnwrap( order.token0, order.token1, pair, tokenShares.weth, order.to, orders.transferGasCosts[address(0)] ); if (!success) { tokenShares.onUnwrapFailed(order.to, wethAmount); } } else { (amount0, amount1) = ITwapPair(pair).burn(order.to); } require(amount0 >= order.value0 && amount1 >= order.value1, 'TD03'); } function _executeBuy(Orders.Order calldata order) external payable { require(msg.sender == address(this), 'TD00'); require(order.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04'); (address pairAddress, ) = orders.getPair(order.token0, order.token1); uint256 amountInMax = tokenShares.sharesToAmount(order.token0, order.value0, order.amountLimit0, order.to); ITwapPair(pairAddress).sync(); bytes memory priceInfo = encodePriceInfo(pairAddress, order.priceAccumulator, order.timestamp); uint256 amountIn; uint256 amountOut; uint256 reserveOut; bool inverted = order.orderType == Orders.BUY_INVERTED_TYPE; { // scope for reserve out logic, avoids stack too deep errors (uint112 reserve0, uint112 reserve1) = ITwapPair(pairAddress).getReserves(); // subtract 1 to prevent reserve going to 0 reserveOut = uint256(inverted ? reserve0 : reserve1).sub(1); } { // scope for partial fill logic, avoids stack too deep errors address oracle = ITwapPair(pairAddress).oracle(); uint256 swapFee = ITwapPair(pairAddress).swapFee(); (amountIn, amountOut) = ITwapOracle(oracle).getSwapAmountInMaxOut( inverted, swapFee, order.value1, priceInfo ); uint256 amountInMaxScaled; if (amountOut > reserveOut) { amountInMaxScaled = amountInMax.mul(reserveOut).ceil_div(order.value1); (amountIn, amountOut) = ITwapOracle(oracle).getSwapAmountInMinOut( inverted, swapFee, reserveOut, priceInfo ); } else { amountInMaxScaled = amountInMax; amountOut = order.value1; // Truncate to desired out } require(amountInMaxScaled >= amountIn, 'TD08'); if (amountInMax > amountIn) { if (order.token0 == tokenShares.weth && order.unwrap) { _forceEtherTransfer(order.to, amountInMax.sub(amountIn)); } else { TransferHelper.safeTransfer(order.token0, order.to, amountInMax.sub(amountIn)); } } TransferHelper.safeTransfer(order.token0, pairAddress, amountIn); } amountOut = amountOut.sub(tolerance[pairAddress]); uint256 amount0Out; uint256 amount1Out; if (inverted) { amount0Out = amountOut; } else { amount1Out = amountOut; } if (order.token1 == tokenShares.weth && order.unwrap) { ITwapPair(pairAddress).swap(amount0Out, amount1Out, address(this), priceInfo); _forceEtherTransfer(order.to, amountOut); } else { ITwapPair(pairAddress).swap(amount0Out, amount1Out, order.to, priceInfo); } } function _executeSell(Orders.Order calldata order) external payable { require(msg.sender == address(this), 'TD00'); require(order.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'TD04'); (address pairAddress, ) = orders.getPair(order.token0, order.token1); ITwapPair(pairAddress).sync(); bytes memory priceInfo = encodePriceInfo(pairAddress, order.priceAccumulator, order.timestamp); bool inverted = order.orderType == Orders.SELL_INVERTED_TYPE; uint256 amountOut = _executeSellHelper(order, inverted, pairAddress, priceInfo); (uint256 amount0Out, uint256 amount1Out) = inverted ? (amountOut, uint256(0)) : (uint256(0), amountOut); if (order.token1 == tokenShares.weth && order.unwrap) { ITwapPair(pairAddress).swap(amount0Out, amount1Out, address(this), priceInfo); _forceEtherTransfer(order.to, amountOut); } else { ITwapPair(pairAddress).swap(amount0Out, amount1Out, order.to, priceInfo); } } function _executeSellHelper( Orders.Order calldata order, bool inverted, address pairAddress, bytes memory priceInfo ) internal returns (uint256 amountOut) { uint256 reserveOut; { // scope for determining reserve out, avoids stack too deep errors (uint112 reserve0, uint112 reserve1) = ITwapPair(pairAddress).getReserves(); // subtract 1 to prevent reserve going to 0 reserveOut = uint256(inverted ? reserve0 : reserve1).sub(1); } { // scope for calculations, avoids stack too deep errors address oracle = ITwapPair(pairAddress).oracle(); uint256 swapFee = ITwapPair(pairAddress).swapFee(); uint256 amountIn = tokenShares.sharesToAmount(order.token0, order.value0, order.amountLimit0, order.to); amountOut = inverted ? ITwapOracle(oracle).getSwapAmount0Out(swapFee, amountIn, priceInfo) : ITwapOracle(oracle).getSwapAmount1Out(swapFee, amountIn, priceInfo); uint256 amountOutMinScaled; if (amountOut > reserveOut) { amountOutMinScaled = order.value1.mul(reserveOut).div(amountOut); uint256 _amountIn = amountIn; (amountIn, amountOut) = ITwapOracle(oracle).getSwapAmountInMinOut( inverted, swapFee, reserveOut, priceInfo ); if (order.token0 == tokenShares.weth && order.unwrap) { _forceEtherTransfer(order.to, _amountIn.sub(amountIn)); } else { TransferHelper.safeTransfer(order.token0, order.to, _amountIn.sub(amountIn)); } } else { amountOutMinScaled = order.value1; } amountOut = amountOut.sub(tolerance[pairAddress]); require(amountOut >= amountOutMinScaled, 'TD37'); TransferHelper.safeTransfer(order.token0, pairAddress, amountIn); } } 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); } } /// @dev The `order` must be verified by calling `Orders.verifyOrder` before calling this function. function performRefund(Orders.Order calldata order, bool shouldRefundEth) internal { bool canOwnerRefund = order.validAfterTimestamp.add(365 days) < block.timestamp; if (order.orderType == Orders.DEPOSIT_TYPE) { address to = canOwnerRefund ? owner : order.to; require(refundTokens(to, order.token0, order.value0, order.token1, order.value1, order.unwrap), 'TD14'); if (shouldRefundEth) { require(refundEth(payable(to), order.gasPrice.mul(order.gasLimit)), 'TD40'); } } else if (order.orderType == Orders.WITHDRAW_TYPE) { (address pair, ) = orders.getPair(order.token0, order.token1); address to = canOwnerRefund ? owner : order.to; require(Orders.refundLiquidity(pair, to, order.liquidity, this._refundLiquidity.selector), 'TD14'); if (shouldRefundEth) { require(refundEth(payable(to), order.gasPrice.mul(order.gasLimit)), 'TD40'); } } else if (order.orderType == Orders.SELL_TYPE || order.orderType == Orders.SELL_INVERTED_TYPE) { address to = canOwnerRefund ? owner : order.to; require(refundToken(order.token0, to, order.value0, order.unwrap), 'TD14'); if (shouldRefundEth) { require(refundEth(payable(to), order.gasPrice.mul(order.gasLimit)), 'TD40'); } } else if (order.orderType == Orders.BUY_TYPE || order.orderType == Orders.BUY_INVERTED_TYPE) { address to = canOwnerRefund ? owner : order.to; require(refundToken(order.token0, to, order.value0, order.unwrap), 'TD14'); if (shouldRefundEth) { require(refundEth(payable(to), order.gasPrice.mul(order.gasLimit)), 'TD40'); } } else { return; } orders.forgetOrder(order.orderId); } function retryRefund(Orders.Order calldata order) external override lock { orders.verifyOrder(order); require(orders.refundFailed[order.orderId], 'TD21'); performRefund(order, false); } function cancelOrder(Orders.Order calldata order) external override lock { orders.verifyOrder(order); require( orders.getOrderStatus(order.orderId, order.validAfterTimestamp) == Orders.OrderStatus.EnqueuedReady, 'TD52' ); require(order.validAfterTimestamp.sub(orders.delay).add(ORDER_CANCEL_TIME) < block.timestamp, 'TD1C'); orders.canceled[order.orderId] = true; performRefund(order, true); } function encodePriceInfo( address pair, uint256 priceAccumulator, uint256 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; 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; 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 RelayerSet(address relayer); event MaxGasLimitSet(uint256 maxGasLimit); event GasPriceInertiaSet(uint256 gasPriceInertia); event MaxGasPriceImpactSet(uint256 maxGasPriceImpact); event TransferGasCostSet(address token, uint256 gasCost); event ToleranceSet(address pair, uint16 amount); event NonRebasingTokenSet(address token, bool isNonRebasing); event OrderDisabled(address pair, Orders.OrderType orderType, bool disabled); event UnwrapFailed(address to, uint256 amount); function factory() external returns (address); function relayer() external returns (address); function owner() external returns (address); function isBot(address bot) external returns (bool); function tolerance(address pair) external returns (uint16); function isNonRebasingToken(address token) external view returns (bool); function gasPriceInertia() external returns (uint256); function gasPrice() external view returns (uint256); function maxGasPriceImpact() external returns (uint256); function maxGasLimit() external returns (uint256); function delay() external returns (uint256); function totalShares(address token) external returns (uint256); function weth() external returns (address); function getTransferGasCost(address token) external returns (uint256); 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, uint256 validAfterTimestamp) external view returns (Orders.OrderStatus); function setOrderDisabled( address pair, Orders.OrderType orderType, bool disabled ) external payable; function setOwner(address _owner) external payable; function setBot(address _bot, bool _isBot) external payable; function setMaxGasLimit(uint256 _maxGasLimit) external payable; function setDelay(uint32 _delay) external payable; function setRelayer(address _relayer) external payable; function setGasPriceInertia(uint256 _gasPriceInertia) external payable; function setMaxGasPriceImpact(uint256 _maxGasPriceImpact) external payable; function setTransferGasCost(address token, uint256 gasCost) external payable; function setTolerance(address pair, uint16 amount) external payable; function setNonRebasingToken(address token, bool isNonRebasing) external payable; function deposit(Orders.DepositParams memory depositParams) external payable returns (uint256 orderId); function withdraw(Orders.WithdrawParams memory withdrawParams) external payable returns (uint256 orderId); function sell(Orders.SellParams memory sellParams) external payable returns (uint256 orderId); function relayerSell(Orders.SellParams memory sellParams) external payable returns (uint256 orderId); function buy(Orders.BuyParams memory buyParams) external payable returns (uint256 orderId); function execute(Orders.Order[] calldata orders) external payable; function retryRefund(Orders.Order calldata order) external; function cancelOrder(Orders.Order calldata order) external; }
// 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 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; interface ITwapOracle { event OwnerSet(address owner); event UniswapPairSet(address uniswapPair); function decimalsConverter() external view returns (int256); function xDecimals() external view returns (uint8); function yDecimals() external view returns (uint8); function owner() external view returns (address); function uniswapPair() external view returns (address); function getPriceInfo() external view returns (uint256 priceAccumulator, uint256 priceTimestamp); function getSpotPrice() external view returns (uint256); function getAveragePrice(uint256 priceAccumulator, uint256 priceTimestamp) external view returns (uint256); function setOwner(address _owner) external; function setUniswapPair(address _uniswapPair) external; function tradeX( uint256 xAfter, uint256 xBefore, uint256 yBefore, bytes calldata data ) external view returns (uint256 yAfter); function tradeY( uint256 yAfter, uint256 yBefore, uint256 xBefore, bytes calldata data ) external view returns (uint256 xAfter); function depositTradeXIn( uint256 xLeft, uint256 xBefore, uint256 yBefore, bytes calldata data ) external view returns (uint256 xIn); function depositTradeYIn( uint256 yLeft, uint256 yBefore, uint256 xBefore, bytes calldata data ) external view returns (uint256 yIn); function getSwapAmount0Out( uint256 swapFee, uint256 amount1In, bytes calldata data ) external view returns (uint256 amount0Out); function getSwapAmount1Out( uint256 swapFee, uint256 amount0In, bytes calldata data ) external view returns (uint256 amount1Out); function getSwapAmountInMaxOut( bool inverse, uint256 swapFee, uint256 _amountOut, bytes calldata data ) external view returns (uint256 amountIn, uint256 amountOut); function getSwapAmountInMinOut( bool inverse, uint256 swapFee, uint256 _amountOut, bytes calldata data ) external view returns (uint256 amountIn, uint256 amountOut); }
// 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; interface IWETH { function deposit() external payable; function transfer(address to, uint256 value) external returns (bool); function withdraw(uint256) external; }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; import './TransferHelper.sol'; import './SafeMath.sol'; import './Math.sol'; import '../interfaces/ITwapPair.sol'; import '../interfaces/ITwapOracle.sol'; library AddLiquidity { using SafeMath for uint256; function addLiquidity( address pair, uint256 amount0Desired, uint256 amount1Desired ) internal view returns ( uint256 amount0, uint256 amount1, uint256 swapToken ) { if (amount0Desired == 0 || amount1Desired == 0) { if (amount0Desired > 0) { swapToken = 1; } else if (amount1Desired > 0) { swapToken = 2; } return (0, 0, swapToken); } (uint256 reserve0, uint256 reserve1) = ITwapPair(pair).getReserves(); if (reserve0 == 0 && reserve1 == 0) { (amount0, amount1) = (amount0Desired, amount1Desired); } else { require(reserve0 > 0 && reserve1 > 0, 'AL07'); uint256 amount1Optimal = amount0Desired.mul(reserve1) / reserve0; if (amount1Optimal <= amount1Desired) { swapToken = 2; (amount0, amount1) = (amount0Desired, amount1Optimal); } else { uint256 amount0Optimal = amount1Desired.mul(reserve0) / reserve1; assert(amount0Optimal <= amount0Desired); swapToken = 1; (amount0, amount1) = (amount0Optimal, amount1Desired); } uint256 totalSupply = ITwapPair(pair).totalSupply(); uint256 liquidityOut = Math.min(amount0.mul(totalSupply) / reserve0, amount1.mul(totalSupply) / reserve1); if (liquidityOut == 0) { amount0 = 0; amount1 = 0; } } } function addLiquidityAndMint( address pair, address to, address token0, address token1, uint256 amount0Desired, uint256 amount1Desired ) external returns ( uint256 amount0Left, uint256 amount1Left, uint256 swapToken ) { uint256 amount0; uint256 amount1; (amount0, amount1, swapToken) = addLiquidity(pair, amount0Desired, amount1Desired); if (amount0 == 0 || amount1 == 0) { return (amount0Desired, amount1Desired, swapToken); } TransferHelper.safeTransfer(token0, pair, amount0); TransferHelper.safeTransfer(token1, pair, amount1); ITwapPair(pair).mint(to); amount0Left = amount0Desired.sub(amount0); amount1Left = amount1Desired.sub(amount1); } function swapDeposit0( address pair, address token0, uint256 amount0, uint256 minSwapPrice, uint16 tolerance, bytes calldata data ) external returns (uint256 amount0Left, uint256 amount1Left) { uint256 amount0In = ITwapPair(pair).getDepositAmount0In(amount0, data); amount1Left = ITwapPair(pair).getSwapAmount1Out(amount0In, data).sub(tolerance); if (amount1Left == 0) { return (amount0, amount1Left); } uint256 price = getPrice(amount0In, amount1Left, pair); require(minSwapPrice == 0 || price >= minSwapPrice, 'AL15'); TransferHelper.safeTransfer(token0, pair, amount0In); ITwapPair(pair).swap(0, amount1Left, address(this), data); amount0Left = amount0.sub(amount0In); } function swapDeposit1( address pair, address token1, uint256 amount1, uint256 maxSwapPrice, uint16 tolerance, bytes calldata data ) external returns (uint256 amount0Left, uint256 amount1Left) { uint256 amount1In = ITwapPair(pair).getDepositAmount1In(amount1, data); amount0Left = ITwapPair(pair).getSwapAmount0Out(amount1In, data).sub(tolerance); if (amount0Left == 0) { return (amount0Left, amount1); } uint256 price = getPrice(amount0Left, amount1In, pair); require(maxSwapPrice == 0 || price <= maxSwapPrice, 'AL16'); TransferHelper.safeTransfer(token1, pair, amount1In); ITwapPair(pair).swap(amount0Left, 0, address(this), data); amount1Left = amount1.sub(amount1In); } function getPrice( uint256 amount0, uint256 amount1, address pair ) internal view returns (uint256) { ITwapOracle oracle = ITwapOracle(ITwapPair(pair).oracle()); return amount1.mul(uint256(oracle.decimalsConverter())).div(amount0); } function _refundDeposit( address to, address token0, address token1, uint256 amount0, uint256 amount1 ) internal { if (amount0 > 0) { TransferHelper.safeTransfer(token0, to, amount0); } if (amount1 > 0) { TransferHelper.safeTransfer(token1, to, amount1); } } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; // 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; 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, Order order); event WithdrawEnqueued(uint256 indexed orderId, Order order); event SellEnqueued(uint256 indexed orderId, Order order); event BuyEnqueued(uint256 indexed orderId, Order order); event OrderDisabled(address pair, Orders.OrderType orderType, bool disabled); event RefundFailed(address indexed to, address indexed token, uint256 amount, bytes data); uint256 public constant DEPOSIT_TYPE = 1; uint256 public constant WITHDRAW_TYPE = 2; uint256 public constant BUY_TYPE = 3; uint256 public constant BUY_INVERTED_TYPE = 4; uint256 public constant SELL_TYPE = 5; uint256 public constant SELL_INVERTED_TYPE = 6; // Note on gas estimation for the full order execution in the UI: // Add (ORDER_BASE_COST + token transfer costs) to the actual gas usage // of the TwapDelay._execute* functions when updating gas cost in the UI. // Remember that ETH unwrap is part of those functions. It is optional, // but also needs to be included in the estimate. uint256 private constant ETHER_TRANSFER_COST = ETHER_TRANSFER_CALL_COST + 2600 + 1504; // Std cost + EIP-2929 acct access cost + Gnosis Safe receive ETH cost uint256 private constant BOT_ETHER_TRANSFER_COST = 10_000; uint256 private constant BUFFER_COST = 10_000; uint256 private constant ORDER_EXECUTED_EVENT_COST = 3700; uint256 private constant EXECUTE_PREPARATION_COST = 30_000; // dequeue + gas calculation before calls to _execute* functions uint256 public constant ETHER_TRANSFER_CALL_COST = 10_000; uint256 public constant PAIR_TRANSFER_COST = 55_000; uint256 public constant REFUND_BASE_COST = BOT_ETHER_TRANSFER_COST + ETHER_TRANSFER_COST + BUFFER_COST + ORDER_EXECUTED_EVENT_COST; uint256 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 Data { uint256 delay; uint256 newestOrderId; uint256 lastProcessedOrderId; mapping(uint256 => bytes32) orderQueue; address factory; uint256 maxGasLimit; uint256 gasPrice; uint256 gasPriceInertia; uint256 maxGasPriceImpact; 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; mapping(uint256 => bool) refundFailed; } struct Order { uint256 orderId; uint256 orderType; uint256 validAfterTimestamp; bool unwrap; uint256 timestamp; uint256 gasLimit; uint256 gasPrice; uint256 liquidity; uint256 value0; // Deposit: share0, Withdraw: amount0Min, Sell: shareIn, Buy: shareInMax uint256 value1; // Deposit: share1, Withdraw: amount1Min, Sell: amountOutMin, Buy: amountOut address token0; // Sell: tokenIn, Buy: tokenIn address token1; // Sell: tokenOut, Buy: tokenOut address to; uint256 minSwapPrice; uint256 maxSwapPrice; bool swap; uint256 priceAccumulator; uint256 amountLimit0; uint256 amountLimit1; } function getOrderStatus( Data storage data, uint256 orderId, uint256 validAfterTimestamp ) internal view returns (OrderStatus) { if (orderId > data.newestOrderId) { return OrderStatus.NonExistent; } if (data.canceled[orderId]) { return OrderStatus.Canceled; } if (data.refundFailed[orderId]) { return OrderStatus.ExecutedFailed; } if (data.orderQueue[orderId] == bytes32(0)) { return OrderStatus.ExecutedSucceeded; } if (validAfterTimestamp >= block.timestamp) { return OrderStatus.EnqueuedWaiting; } return OrderStatus.EnqueuedReady; } function getPair( Data storage data, address tokenA, address tokenB ) internal view returns (address pair, bool inverted) { pair = ITwapFactory(data.factory).getPair(tokenA, tokenB); require(pair != address(0), 'OS17'); inverted = tokenA > tokenB; } function getDepositDisabled(Data storage data, address pair) internal view returns (bool) { return data.orderDisabled[pair] & DEPOSIT_MASK != 0; } function getWithdrawDisabled(Data storage data, address pair) internal view returns (bool) { return data.orderDisabled[pair] & WITHDRAW_MASK != 0; } function getSellDisabled(Data storage data, address pair) internal view returns (bool) { return data.orderDisabled[pair] & SELL_MASK != 0; } function getBuyDisabled(Data storage data, address pair) internal view returns (bool) { return data.orderDisabled[pair] & BUY_MASK != 0; } function 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 markRefundFailed(Data storage data) internal { data.refundFailed[data.lastProcessedOrderId] = true; } /// @dev The passed in order.oderId is ignored and overwritten with the correct value, i.e. an updated data.newestOrderId. /// This is done to ensure atomicity of these two actions while optimizing gas usage - adding an order to the queue and incrementing /// data.newestOrderId (which should not be done anywhere else in the contract). /// Must only be called on verified orders. function enqueueOrder(Data storage data, Order memory order) internal { order.orderId = ++data.newestOrderId; data.orderQueue[order.orderId] = getOrderDigest(order); } struct DepositParams { address token0; address token1; uint256 amount0; uint256 amount1; uint256 minSwapPrice; uint256 maxSwapPrice; bool wrap; bool swap; address to; uint256 gasLimit; uint32 submitDeadline; } function deposit( Data storage data, DepositParams calldata depositParams, TokenShares.Data storage tokenShares ) external { { // scope for checks, avoids stack too deep errors uint256 token0TransferCost = data.transferGasCosts[depositParams.token0]; uint256 token1TransferCost = data.transferGasCosts[depositParams.token1]; require(token0TransferCost != 0 && token1TransferCost != 0, 'OS0F'); checkOrderParams( data, depositParams.to, depositParams.gasLimit, depositParams.submitDeadline, ORDER_BASE_COST.add(token0TransferCost).add(token1TransferCost) ); } require(depositParams.amount0 != 0 || depositParams.amount1 != 0, 'OS25'); (address pairAddress, bool inverted) = getPair(data, depositParams.token0, depositParams.token1); require(!getDepositDisabled(data, pairAddress), 'OS46'); { // scope for value, avoids stack too deep errors uint256 value = msg.value; // allocate gas refund if (depositParams.wrap) { if (depositParams.token0 == tokenShares.weth) { value = msg.value.sub(depositParams.amount0, 'OS1E'); } else if (depositParams.token1 == tokenShares.weth) { value = msg.value.sub(depositParams.amount1, 'OS1E'); } } allocateGasRefund(data, value, depositParams.gasLimit); } uint256 shares0 = tokenShares.amountToShares( inverted ? depositParams.token1 : depositParams.token0, inverted ? depositParams.amount1 : depositParams.amount0, depositParams.wrap ); uint256 shares1 = tokenShares.amountToShares( inverted ? depositParams.token0 : depositParams.token1, inverted ? depositParams.amount0 : depositParams.amount1, depositParams.wrap ); (uint256 priceAccumulator, uint256 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo(); Order memory order = Order( 0, DEPOSIT_TYPE, timestamp + data.delay, // validAfterTimestamp depositParams.wrap, timestamp, depositParams.gasLimit, data.gasPrice, 0, // liquidity shares0, shares1, inverted ? depositParams.token1 : depositParams.token0, inverted ? depositParams.token0 : depositParams.token1, depositParams.to, depositParams.minSwapPrice, depositParams.maxSwapPrice, depositParams.swap, priceAccumulator, inverted ? depositParams.amount1 : depositParams.amount0, inverted ? depositParams.amount0 : depositParams.amount1 ); enqueueOrder(data, order); emit DepositEnqueued(order.orderId, order); } struct WithdrawParams { address token0; address token1; uint256 liquidity; uint256 amount0Min; uint256 amount1Min; bool unwrap; address to; uint256 gasLimit; uint32 submitDeadline; } function withdraw(Data storage data, WithdrawParams calldata withdrawParams) external { (address pair, bool inverted) = getPair(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); Order memory order = Order( 0, WITHDRAW_TYPE, block.timestamp + data.delay, // validAfterTimestamp withdrawParams.unwrap, 0, // timestamp withdrawParams.gasLimit, data.gasPrice, withdrawParams.liquidity, inverted ? withdrawParams.amount1Min : withdrawParams.amount0Min, inverted ? withdrawParams.amount0Min : withdrawParams.amount1Min, inverted ? withdrawParams.token1 : withdrawParams.token0, inverted ? withdrawParams.token0 : withdrawParams.token1, withdrawParams.to, 0, // minSwapPrice 0, // maxSwapPrice false, // swap 0, // priceAccumulator 0, // amountLimit0 0 // amountLimit1 ); enqueueOrder(data, order); emit WithdrawEnqueued(order.orderId, order); } struct SellParams { address tokenIn; address tokenOut; uint256 amountIn; uint256 amountOutMin; bool wrapUnwrap; address to; uint256 gasLimit; uint32 submitDeadline; } function sell( Data storage data, SellParams calldata sellParams, TokenShares.Data storage tokenShares ) external { uint256 tokenTransferCost = data.transferGasCosts[sellParams.tokenIn]; require(tokenTransferCost != 0, 'OS0F'); checkOrderParams( data, sellParams.to, sellParams.gasLimit, sellParams.submitDeadline, ORDER_BASE_COST.add(tokenTransferCost) ); (address pairAddress, bool inverted) = sellHelper(data, tokenShares, sellParams); (uint256 priceAccumulator, uint256 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo(); uint256 shares = tokenShares.amountToShares(sellParams.tokenIn, sellParams.amountIn, sellParams.wrapUnwrap); Order memory order = Order( 0, inverted ? SELL_INVERTED_TYPE : SELL_TYPE, timestamp + data.delay, // validAfterTimestamp sellParams.wrapUnwrap, timestamp, sellParams.gasLimit, data.gasPrice, 0, // liquidity shares, sellParams.amountOutMin, sellParams.tokenIn, sellParams.tokenOut, sellParams.to, 0, // minSwapPrice 0, // maxSwapPrice false, // swap priceAccumulator, sellParams.amountIn, 0 // amountLimit1 ); enqueueOrder(data, order); emit SellEnqueued(order.orderId, order); } function relayerSell( Data storage data, SellParams calldata sellParams, TokenShares.Data storage tokenShares ) external { checkOrderParams(data, sellParams.to, sellParams.gasLimit, sellParams.submitDeadline, ORDER_BASE_COST); (, bool inverted) = sellHelper(data, tokenShares, sellParams); uint256 shares = tokenShares.amountToSharesWithoutTransfer( sellParams.tokenIn, sellParams.amountIn, sellParams.wrapUnwrap ); Order memory order = Order( 0, inverted ? SELL_INVERTED_TYPE : SELL_TYPE, block.timestamp + data.delay, // validAfterTimestamp false, // Never wrap/unwrap block.timestamp, sellParams.gasLimit, data.gasPrice, 0, // liquidity shares, sellParams.amountOutMin, sellParams.tokenIn, sellParams.tokenOut, sellParams.to, 0, // minSwapPrice 0, // maxSwapPrice false, // swap 0, // priceAccumulator - oracleV3 pairs don't need priceAccumulator sellParams.amountIn, 0 // amountLimit1 ); enqueueOrder(data, order); emit SellEnqueued(order.orderId, order); } function sellHelper( Data storage data, TokenShares.Data storage tokenShares, SellParams calldata sellParams ) internal returns (address pairAddress, bool inverted) { require(sellParams.amountIn != 0, 'OS24'); (pairAddress, inverted) = getPair(data, sellParams.tokenIn, sellParams.tokenOut); require(!getSellDisabled(data, pairAddress), 'OS13'); // allocate gas refund uint256 value = msg.value; if (sellParams.wrapUnwrap && sellParams.tokenIn == tokenShares.weth) { value = msg.value.sub(sellParams.amountIn, 'OS1E'); } allocateGasRefund(data, value, sellParams.gasLimit); } struct BuyParams { address tokenIn; address tokenOut; uint256 amountInMax; uint256 amountOut; bool wrapUnwrap; address to; uint256 gasLimit; uint32 submitDeadline; } function buy( Data storage data, BuyParams calldata buyParams, TokenShares.Data storage tokenShares ) external { 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, bool inverted) = getPair(data, buyParams.tokenIn, buyParams.tokenOut); require(!getBuyDisabled(data, pairAddress), 'OS49'); uint256 value = msg.value; // allocate gas refund if (buyParams.tokenIn == tokenShares.weth && buyParams.wrapUnwrap) { value = msg.value.sub(buyParams.amountInMax, 'OS1E'); } allocateGasRefund(data, value, buyParams.gasLimit); uint256 shares = tokenShares.amountToShares(buyParams.tokenIn, buyParams.amountInMax, buyParams.wrapUnwrap); (uint256 priceAccumulator, uint256 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo(); Order memory order = Order( 0, inverted ? BUY_INVERTED_TYPE : BUY_TYPE, timestamp + data.delay, // validAfterTimestamp buyParams.wrapUnwrap, timestamp, buyParams.gasLimit, data.gasPrice, 0, // liquidity shares, buyParams.amountOut, buyParams.tokenIn, buyParams.tokenOut, buyParams.to, 0, // minSwapPrice 0, // maxSwapPrice false, // swap priceAccumulator, buyParams.amountInMax, 0 // amountLimit1 ); enqueueOrder(data, order); emit BuyEnqueued(order.orderId, order); } function checkOrderParams( 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); data.gasPrice = data.gasPrice.mul(data.gasPriceInertia.sub(scale)).add(tx.gasprice.mul(scale)).div( data.gasPriceInertia ); } function setMaxGasLimit(Data storage data, uint256 _maxGasLimit) external { require(_maxGasLimit != data.maxGasLimit, 'OS01'); require(_maxGasLimit <= 10000000, 'OS2B'); data.maxGasLimit = _maxGasLimit; emit MaxGasLimitSet(_maxGasLimit); } function setGasPriceInertia(Data storage data, uint256 _gasPriceInertia) external { require(_gasPriceInertia != data.gasPriceInertia, 'OS01'); require(_gasPriceInertia >= 1, 'OS35'); data.gasPriceInertia = _gasPriceInertia; emit GasPriceInertiaSet(_gasPriceInertia); } function setMaxGasPriceImpact(Data storage data, uint256 _maxGasPriceImpact) external { require(_maxGasPriceImpact != data.maxGasPriceImpact, 'OS01'); require(_maxGasPriceImpact <= data.gasPriceInertia, 'OS33'); data.maxGasPriceImpact = _maxGasPriceImpact; emit MaxGasPriceImpactSet(_maxGasPriceImpact); } function setTransferGasCost( Data storage data, address token, uint256 gasCost ) external { require(gasCost != data.transferGasCosts[token], 'OS01'); data.transferGasCosts[token] = gasCost; emit TransferGasCostSet(token, gasCost); } function refundLiquidity( address pair, address to, uint256 liquidity, bytes4 selector ) internal returns (bool) { if (liquidity == 0) { return true; } (bool success, bytes memory data) = address(this).call{ gas: PAIR_TRANSFER_COST }( abi.encodeWithSelector(selector, pair, to, liquidity, false) ); if (!success) { emit RefundFailed(to, pair, liquidity, data); } return success; } function dequeueOrder(Data storage data, uint256 orderId) internal { ++data.lastProcessedOrderId; require(orderId == data.lastProcessedOrderId, 'OS72'); } function forgetOrder(Data storage data, uint256 orderId) internal { delete data.orderQueue[orderId]; } function forgetLastProcessedOrder(Data storage data) internal { delete data.orderQueue[data.lastProcessedOrderId]; } function getOrderDigest(Order memory order) internal pure returns (bytes32) { // Used to avoid the 'stack too deep' error. bytes memory partialOrderData = abi.encodePacked( order.orderId, order.orderType, order.validAfterTimestamp, order.unwrap, order.timestamp, order.gasLimit, order.gasPrice, order.liquidity, order.value0, order.value1, order.token0, order.token1, order.to, order.minSwapPrice ); return keccak256( abi.encodePacked( partialOrderData, order.maxSwapPrice, order.swap, order.priceAccumulator, order.amountLimit0, order.amountLimit1 ) ); } function verifyOrder(Data storage data, Order memory order) external view { require(getOrderDigest(order) == data.orderQueue[order.orderId], 'OS71'); } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) library SafeMath { int256 private constant _INT256_MIN = -2**255; function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x, 'SM4E'); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { z = sub(x, y, 'SM12'); } function sub( uint256 x, uint256 y, string memory message ) internal pure returns (uint256 z) { require((z = x - y) <= x, message); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x, 'SM2A'); } function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, 'SM43'); return a / b; } function ceil_div(uint256 a, uint256 b) internal pure returns (uint256 c) { c = div(a, b); if (a != mul(b, c)) { return add(c, 1); } } function toUint32(uint256 n) internal pure returns (uint32) { require(n <= type(uint32).max, 'SM50'); return uint32(n); } function toUint64(uint256 n) internal pure returns (uint64) { require(n <= type(uint64).max, 'SM54'); return uint64(n); } function toUint112(uint256 n) internal pure returns (uint112) { require(n <= type(uint112).max, 'SM51'); return uint112(n); } function toInt256(uint256 unsigned) internal pure returns (int256 signed) { require(unsigned <= uint256(type(int256).max), 'SM34'); signed = int256(unsigned); } // int256 function add(int256 a, int256 b) internal pure returns (int256 c) { c = a + b; require((b >= 0 && c >= a) || (b < 0 && c < a), 'SM4D'); } function sub(int256 a, int256 b) internal pure returns (int256 c) { c = a - b; require((b >= 0 && c <= a) || (b < 0 && c > a), 'SM11'); } function mul(int256 a, int256 b) internal pure returns (int256 c) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } require(!(a == -1 && b == _INT256_MIN), 'SM29'); c = a * b; require(c / a == b, 'SM29'); } function div(int256 a, int256 b) internal pure returns (int256) { require(b != 0, 'SM43'); require(!(b == -1 && a == _INT256_MIN), 'SM42'); return a / b; } function neg_floor_div(int256 a, int256 b) internal pure returns (int256 c) { c = div(a, b); if ((a < 0 && b > 0) || (a >= 0 && b < 0)) { if (a != mul(b, c)) { c = sub(c, 1); } } } }
// SPDX-License-Identifier: GPL-3.0-or-later // Deployed with donations via Gitcoin GR9 pragma solidity 0.7.6; import '../interfaces/IERC20.sol'; import '../interfaces/IWETH.sol'; import './SafeMath.sol'; import './TransferHelper.sol'; library TokenShares { using SafeMath for uint256; using TransferHelper for address; uint256 private constant PRECISION = 10**18; uint256 private constant TOLERANCE = 10**18 + 10**16; uint256 private constant TOTAL_SHARES_PRECISION = 10**18; event UnwrapFailed(address to, uint256 amount); struct Data { mapping(address => uint256) totalShares; mapping(address => bool) nonRebasingToken; address weth; // represents wrapped native currency (WETH or WMATIC) } function sharesToAmount( Data storage data, address token, uint256 share, uint256 amountLimit, address refundTo ) external returns (uint256) { if (share == 0) { return 0; } if (token == data.weth || data.nonRebasingToken[token]) { return share; } uint256 totalTokenShares = data.totalShares[token]; require(totalTokenShares >= share, 'TS3A'); uint256 balance = IERC20(token).balanceOf(address(this)); uint256 value = balance.mul(share).div(totalTokenShares); data.totalShares[token] = totalTokenShares.sub(share); if (amountLimit > 0) { uint256 amountLimitWithTolerance = amountLimit.mul(TOLERANCE).div(PRECISION); if (value > amountLimitWithTolerance) { TransferHelper.safeTransfer(token, refundTo, value.sub(amountLimitWithTolerance)); return amountLimitWithTolerance; } } return value; } function amountToShares( Data storage data, address token, uint256 amount, bool wrap ) external returns (uint256) { if (amount == 0) { return 0; } if (token == 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 if (data.nonRebasingToken[token]) { token.safeTransferFrom(msg.sender, address(this), amount); return amount; } else { uint256 balanceBefore = IERC20(token).balanceOf(address(this)); token.safeTransferFrom(msg.sender, address(this), amount); uint256 balanceAfter = IERC20(token).balanceOf(address(this)); return amountToSharesHelper(data, token, balanceBefore, balanceAfter); } } function amountToSharesWithoutTransfer( Data storage data, address token, uint256 amount, bool wrap ) external returns (uint256) { if (token == data.weth) { if (wrap) { // require(msg.value >= amount, 'TS03'); // Duplicate check in TwapRelayer.sell IWETH(token).deposit{ value: amount }(); } return amount; } else if (data.nonRebasingToken[token]) { return amount; } else { uint256 balanceAfter = IERC20(token).balanceOf(address(this)); uint256 balanceBefore = balanceAfter.sub(amount); return amountToSharesHelper(data, token, balanceBefore, balanceAfter); } } function amountToSharesHelper( Data storage data, address token, uint256 balanceBefore, uint256 balanceAfter ) internal returns (uint256) { uint256 totalTokenShares = data.totalShares[token]; require(balanceBefore > 0 || totalTokenShares == 0, 'TS30'); require(balanceAfter > balanceBefore, 'TS2C'); if (balanceBefore > 0) { if (totalTokenShares == 0) { totalTokenShares = balanceBefore.mul(TOTAL_SHARES_PRECISION); } uint256 newShares = totalTokenShares.mul(balanceAfter).div(balanceBefore); require(balanceAfter < type(uint256).max.div(newShares), 'TS73'); // to prevent overflow at execution data.totalShares[token] = newShares; return newShares - totalTokenShares; } else { totalTokenShares = balanceAfter.mul(TOTAL_SHARES_PRECISION); require(totalTokenShares < type(uint256).max.div(totalTokenShares), 'TS73'); // to prevent overflow at execution data.totalShares[token] = totalTokenShares; return totalTokenShares; } } function onUnwrapFailed( 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; // 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; 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); } // unwraps wrapped native currency function _unwrapWeth( uint256 ethAmount, address weth, address to, uint256 gasLimit ) internal returns (bool) { IWETH(weth).withdraw(ethAmount); (bool success, ) = to.call{ value: ethAmount, gas: gasLimit }(''); return success; } function withdrawAndUnwrap( address token0, address token1, address pair, address weth, address to, uint256 gasLimit ) external returns ( bool, uint256, uint256, uint256 ) { bool isToken0Weth = token0 == weth; address otherToken = isToken0Weth ? token1 : token0; uint256 balanceBefore = IERC20(otherToken).balanceOf(address(this)); (uint256 amount0, uint256 amount1) = ITwapPair(pair).burn(address(this)); _transferToken(balanceBefore, otherToken, to); bool success = _unwrapWeth(isToken0Weth ? amount0 : amount1, weth, to, gasLimit); return (success, isToken0Weth ? amount0 : amount1, amount0, amount1); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": { "contracts/libraries/TokenShares.sol": { "TokenShares": "0x1441f0c929fdcb2d13d35d892ebca928a45b9d79" }, "contracts/libraries/Orders.sol": { "Orders": "0xf5352c5035344d1ac36d2e4c2b6a237b13e82ffc" }, "contracts/libraries/AddLiquidity.sol": { "AddLiquidity": "0x0ec2323adafbebc6c80257c7359692bcceb0b3f1" }, "contracts/libraries/WithdrawHelper.sol": { "WithdrawHelper": "0x19f6bc0755fd4a465b3961fb335d6e55ab8b9eaa" } } }
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":"uint256","name":"gasPriceInertia","type":"uint256"}],"name":"GasPriceInertiaSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxGasLimit","type":"uint256"}],"name":"MaxGasLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxGasPriceImpact","type":"uint256"}],"name":"MaxGasPriceImpactSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"bool","name":"isNonRebasing","type":"bool"}],"name":"NonRebasingTokenSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":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":"relayer","type":"address"}],"name":"RelayerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"uint16","name":"amount","type":"uint16"}],"name":"ToleranceSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"gasCost","type":"uint256"}],"name":"TransferGasCostSet","type":"event"},{"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":"uint256","name":"orderId","type":"uint256"},{"internalType":"uint256","name":"orderType","type":"uint256"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"_executeBuy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"uint256","name":"orderType","type":"uint256"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"_executeDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"uint256","name":"orderType","type":"uint256"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"_executeSell","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"uint256","name":"orderType","type":"uint256"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"_executeWithdraw","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"name":"_refundLiquidity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"share","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"}],"name":"_refundToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"uint256","name":"share0","type":"uint256"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"share1","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"}],"name":"_refundTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"bool","name":"wrapUnwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.BuyParams","name":"buyParams","type":"tuple"}],"name":"buy","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"uint256","name":"orderType","type":"uint256"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"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":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"uint256","name":"orderType","type":"uint256"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order[]","name":"_orders","type":"tuple[]"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"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":"address","name":"pair","type":"address"}],"name":"getDepositDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"}],"name":"getOrderStatus","outputs":[{"internalType":"enum Orders.OrderStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getSellDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"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":"address","name":"","type":"address"}],"name":"isBot","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"isNonRebasingToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"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":[],"name":"relayer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"wrapUnwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.SellParams","name":"sellParams","type":"tuple"}],"name":"relayerSell","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"uint256","name":"orderType","type":"uint256"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"retryRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"wrapUnwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.SellParams","name":"sellParams","type":"tuple"}],"name":"sell","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_bot","type":"address"},{"internalType":"bool","name":"_isBot","type":"bool"}],"name":"setBot","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_delay","type":"uint32"}],"name":"setDelay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasPriceInertia","type":"uint256"}],"name":"setGasPriceInertia","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxGasLimit","type":"uint256"}],"name":"setMaxGasLimit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxGasPriceImpact","type":"uint256"}],"name":"setMaxGasPriceImpact","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"isNonRebasing","type":"bool"}],"name":"setNonRebasingToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"disabled","type":"bool"}],"name":"setOrderDisabled","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_relayer","type":"address"}],"name":"setRelayer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"},{"internalType":"uint16","name":"amount","type":"uint16"}],"name":"setTolerance","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"gasCost","type":"uint256"}],"name":"setTransferGasCost","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tolerance","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.WithdrawParams","name":"withdrawParams","type":"tuple"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620055f3380380620055f3833981016040819052620000349162000176565b600480546001600160a01b038086166001600160a01b031992831617835560108054831633179055838116600090815260126020526040808220805460ff191660011790553a600655600f805493881693909416929092179092556107088255624c4b406005556301312d00600755620f42406008555163b2456a0760e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc9263b2456a0792620000e592909182916127109101620001d3565b60006040518083038186803b158015620000fe57600080fd5b505af415801562000113573d6000803e3d6000fd5b505050507f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe233604051620001489190620001bf565b60405180910390a1505050620001f2565b80516001600160a01b03811681146200017157600080fd5b919050565b6000806000606084860312156200018b578283fd5b620001968462000159565b9250620001a66020850162000159565b9150620001b66040850162000159565b90509250925092565b6001600160a01b0391909116815260200190565b9283526001600160a01b03919091166020830152604082015260600190565b6153f180620002026000396000f3fe6080604052600436106102975760003560e01c80638406c0791161015a578063ba4d5312116100c1578063e29577ee1161007a578063e29577ee146106b9578063e30a4993146106cc578063e5b1be65146106e1578063e5e7988e146106f4578063e6a0cc9414610714578063fe173b97146107295761029e565b8063ba4d53121461061e578063bf6b874e14610631578063c45a015514610651578063c9cd976014610666578063ceb0981f14610679578063d22e9242146106a65761029e565b80639d08ebb5116101135780639d08ebb514610585578063a70885c114610598578063ab13d9bd146105c5578063af482b58146105d8578063b32ac936146105f8578063b5540b2b1461060b5761029e565b80638406c0791461050257806389e707ad146105175780638da5cb5b1461052a578063945317131461053f578063953556e2146105525780639718f627146105655761029e565b80635051349a116101fe5780636a42b8f8116101b75780636a42b8f8146104725780636de3c67c1461048757806370190d4c1461049c57806377632ec2146104bc578063793ab297146104dc5780637f6a1caf146104ef5761029e565b80635051349a146103ef578063576b332b1461040f57806357a62a4f146104225780635e45da23146104375780636548e9bc1461044c57806368f63a341461045f5761029e565b8063303a892b11610250578063303a892b14610354578063342aa8b5146103675780633bbac5791461037a5780633ed76f171461039a5780633fc8cef3146103ad5780634c016016146103cf5761029e565b806302241c70146102a357806310348665146102c557806313af4035146102d85780631776834a146102eb57806320a68fab146102fe5780632c391c7b146103345761029e565b3661029e57005b600080fd5b3480156102af57600080fd5b506102c36102be36600461491f565b61073e565b005b6102c36102d3366004614a16565b61088f565b6102c36102e636600461460a565b6108fe565b6102c36102f9366004614975565b610999565b34801561030a57600080fd5b5061031e61031936600461460a565b610a30565b60405161032b9190614dd5565b60405180910390f35b34801561034057600080fd5b5061031e61034f36600461460a565b610a44565b6102c361036236600461491f565b610a62565b6102c3610375366004614743565b610e34565b34801561038657600080fd5b5061031e61039536600461460a565b610ec0565b6102c36103a8366004614682565b610ed5565b3480156103b957600080fd5b506103c2610ef5565b60405161032b9190614c47565b3480156103db57600080fd5b5061031e6103ea36600461460a565b610f04565b6104026103fd3660046148f1565b610f10565b60405161032b91906152c4565b61040261041d366004614931565b610fb3565b34801561042e57600080fd5b50610402611016565b34801561044357600080fd5b5061040261101c565b6102c361045a36600461460a565b611022565b6102c361046d36600461491f565b6110eb565b34801561047e57600080fd5b50610402611332565b34801561049357600080fd5b50610402611338565b3480156104a857600080fd5b506102c36104b736600461491f565b61133e565b3480156104c857600080fd5b5061031e6104d7366004614975565b611409565b6102c36104ea3660046147c8565b61141e565b6102c36104fd36600461477b565b6114c6565b34801561050e57600080fd5b506103c261155a565b6102c361052536600461491f565b611569565b34801561053657600080fd5b506103c2611c49565b6102c361054d366004614975565b611c58565b6104026105603660046148f1565b611cbc565b34801561057157600080fd5b5061040261058036600461460a565b611d4a565b61040261059336600461490d565b611d65565b3480156105a457600080fd5b506105b86105b336600461460a565b611dcb565b60405161032b91906152b5565b6102c36105d3366004614743565b611de1565b3480156105e457600080fd5b5061031e6105f336600461460a565b611ed6565b6102c3610606366004614975565b611ee2565b6102c3610619366004614826565b611f46565b61040261062c3660046148f1565b6122dd565b34801561063d57600080fd5b5061040261064c36600461460a565b612343565b34801561065d57600080fd5b506103c261235e565b6102c3610674366004614642565b61236d565b34801561068557600080fd5b506106996106943660046149a5565b61239c565b60405161032b9190614e36565b6102c36106b43660046147fb565b6123b2565b6102c36106c736600461491f565b612444565b3480156106d857600080fd5b506104026127ca565b6102c36106ef3660046146f1565b6127d0565b34801561070057600080fd5b5061031e61070f36600461460a565b6129cf565b34801561072057600080fd5b506104026129db565b34801561073557600080fd5b506104026129e1565b601454156107675760405162461bcd60e51b815260040161075e90614e68565b60405180910390fd5b6001601455604051632e548b5b60e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc90632e548b5b906107a69060009085906004016151ac565b60006040518083038186803b1580156107be57600080fd5b505af41580156107d2573d6000803e3d6000fd5b50600292506107df915050565b6107f06000833560408501356129e7565b60058111156107fb57fe5b146108185760405162461bcd60e51b815260040161075e90614fd0565b426108416201518061083b60008001548560400135612a7690919063ffffffff16565b90612a9f565b1061085e5760405162461bcd60e51b815260040161075e90614e86565b80356000908152600a60205260409020805460ff19166001908117909155610887908290612ae0565b506000601455565b6010546001600160a01b031633146108b95760405162461bcd60e51b815260040161075e90614f1c565b63ffffffff81166000556040517f63e09f16584208fba1fc7ff64c62b00f07bec177c0d97ca6689891b1e77a35c7906108f390839061533b565b60405180910390a150565b6010546001600160a01b031633146109285760405162461bcd60e51b815260040161075e90614f1c565b6001600160a01b03811661094e5760405162461bcd60e51b815260040161075e9061500c565b601080546001600160a01b0319166001600160a01b0383161790556040517f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe2906108f3908390614c47565b6010546001600160a01b031633146109c35760405162461bcd60e51b815260040161075e90614f1c565b604051636702eca360e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc90636702eca3906109fd90600090859060040161526c565b60006040518083038186803b158015610a1557600080fd5b505af4158015610a29573d6000803e3d6000fd5b5050505050565b6000610a3c8183612d77565b90505b919050565b6001600160a01b03166000908152600e602052604090205460ff1690565b333014610a815760405162461bcd60e51b815260040161075e90614f1c565b426202a3008260400135011015610aaa5760405162461bcd60e51b815260040161075e90614fb2565b6000610adc610ac16101608401610140850161460a565b610ad36101808501610160860161460a565b60009190612dab565b5090506000806000610aee8585612e78565b91945092509050610b0761020086016101e08701614897565b8015610b1257508015155b15610d16576000610b2d858761020001358860800135613124565b90508315801590610b3e5750816001145b15610c24576000730ec2323adafbebc6c80257c7359692bcceb0b3f163d0b0a9bc87610b726101608b016101408c0161460a565b6001600160a01b038a16600090815260136020526040908190205490516001600160e01b031960e086901b168152610bbe9392918b916101a08f01359161ffff16908a90600401614d4d565b604080518083038186803b158015610bd557600080fd5b505af4158015610be9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0d91906149c6565b9095509050610c1c8482612a9f565b935050610d14565b8215801590610c335750816002145b15610d14576000730ec2323adafbebc6c80257c7359692bcceb0b3f163adf5f8f387610c676101808b016101608c0161460a565b6001600160a01b038a16600090815260136020526040908190205490516001600160e01b031960e086901b168152610cb39392918a916101c08f01359161ffff16908a90600401614d4d565b604080518083038186803b158015610cca57600080fd5b505af4158015610cde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d0291906149c6565b94509050610d108582612a9f565b9450505b505b8215801590610d2457508115155b15610df457730ec2323adafbebc6c80257c7359692bcceb0b3f1637a528bd285610d566101a089016101808a0161460a565b610d686101608a016101408b0161460a565b610d7a6101808b016101608c0161460a565b88886040518763ffffffff1660e01b8152600401610d9d96959493929190614cb0565b60606040518083038186803b158015610db557600080fd5b505af4158015610dc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ded91906149e9565b5090935091505b610a29610e096101a08701610180880161460a565b610e1b6101608801610140890161460a565b610e2d61018089016101608a0161460a565b8686613242565b6010546001600160a01b03163314610e5e5760405162461bcd60e51b815260040161075e90614f1c565b6001600160a01b03821660009081526012602052604090819020805460ff1916831515179055517f70af441dbb427737e6a5ef2cf5b664321011765ce1d19ce4a69cd024e69d4f2f90610eb49084908490614d9d565b60405180910390a15050565b60126020526000908152604090205460ff1681565b610ee1858786846127d0565b610eed838784846127d0565b505050505050565b600f546001600160a01b031690565b6000610a3c8183613264565b6000601454600014610f345760405162461bcd60e51b815260040161075e90614e68565b600160145560405162c44ff160e31b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc906306227f8890610f75906000908690600d9060040161509e565b60006040518083038186803b158015610f8d57600080fd5b505af4158015610fa1573d6000803e3d6000fd5b50506001546000601455949350505050565b6000601454600014610fd75760405162461bcd60e51b815260040161075e90614e68565b6001601455604051636587992160e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc90636587992190610f759060009086906004016151c1565b60085490565b60055490565b6010546001600160a01b0316331461104c5760405162461bcd60e51b815260040161075e90614f1c565b6011546001600160a01b038281169116141561107a5760405162461bcd60e51b815260040161075e90614f3a565b6001600160a01b0381166110a05760405162461bcd60e51b815260040161075e9061500c565b601180546001600160a01b0319166001600160a01b0383161790556040517fb7041340e0c2a075059bf0488a71c767724be15dae8e737f8460007325e8d857906108f3908390614c47565b33301461110a5760405162461bcd60e51b815260040161075e90614f1c565b426202a30082604001350110156111335760405162461bcd60e51b815260040161075e90614fb2565b600061114a610ac16101608401610140850161460a565b509050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561118857600080fd5b505af115801561119c573d6000803e3d6000fd5b5050505060006111b6828461020001358560800135613124565b9050602083013560061460006111ce8583868661326d565b9050600080836111e0576000836111e4565b8260005b600f5491935091506001600160a01b031661120761018089016101608a0161460a565b6001600160a01b031614801561122857506112286080880160608901614897565b156112b35760405163022c0d9f60e01b81526001600160a01b0387169063022c0d9f9061125f908590859030908b906004016152e6565b600060405180830381600087803b15801561127957600080fd5b505af115801561128d573d6000803e3d6000fd5b506112ae92506112a89150506101a089016101808a0161460a565b8461377c565b611329565b6001600160a01b03861663022c0d9f83836112d66101a08c016101808d0161460a565b896040518563ffffffff1660e01b81526004016112f694939291906152e6565b600060405180830381600087803b15801561131057600080fd5b505af1158015611324573d6000803e3d6000fd5b505050505b50505050505050565b60005490565b60075490565b6014541561135e5760405162461bcd60e51b815260040161075e90614e68565b6001601455604051632e548b5b60e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc90632e548b5b9061139d9060009085906004016151ac565b60006040518083038186803b1580156113b557600080fd5b505af41580156113c9573d6000803e3d6000fd5b50505081356000908152600c602052604090205460ff1690506113fe5760405162461bcd60e51b815260040161075e90614ec2565b610887816000612ae0565b6000908152600a602052604090205460ff1690565b6010546001600160a01b031633146114485760405162461bcd60e51b815260040161075e90614f1c565b600a61ffff8216111561146d5760405162461bcd60e51b815260040161075e90614f94565b6001600160a01b03821660009081526013602052604090819020805461ffff191661ffff8416179055517f6b4044e33be5af8fcdb7449c49137010eede3c8c06d5d08067151a7ace17266d90610eb49084908490614db8565b6010546001600160a01b031633146114f05760405162461bcd60e51b815260040161075e90614f1c565b60405163146bce4f60e31b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc9063a35e72789061152e90600090879087908790600401615048565b60006040518083038186803b15801561154657600080fd5b505af4158015611329573d6000803e3d6000fd5b6011546001600160a01b031681565b3330146115885760405162461bcd60e51b815260040161075e90614f1c565b426202a30082604001350110156115b15760405162461bcd60e51b815260040161075e90614fb2565b60006115c8610ac16101608401610140850161460a565b5090506000731441f0c929fdcb2d13d35d892ebca928a45b9d7963a8d669b4600d6115fb6101608701610140880161460a565b6101008701356102208801356116196101a08a016101808b0161460a565b6040518663ffffffff1660e01b815260040161163995949392919061527a565b60206040518083038186803b15801561165157600080fd5b505af4158015611665573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611689919061498d565b9050816001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156116c657600080fd5b505af11580156116da573d6000803e3d6000fd5b5050505060006116f4838561020001358660800135613124565b905060008060008060048860200135149050600080886001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401604080518083038186803b15801561174157600080fd5b505afa158015611755573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117799190614943565b9150915061179e60018461178d578261178f565b835b6001600160701b031690612a76565b935050506000876001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b1580156117dd57600080fd5b505afa1580156117f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118159190614626565b90506000886001600160a01b03166354cf2aeb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561185257600080fd5b505afa158015611866573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188a919061498d565b9050816001600160a01b031663daab4b6e84838d61012001358b6040518563ffffffff1660e01b81526004016118c39493929190614de0565b604080518083038186803b1580156118da57600080fd5b505afa1580156118ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191291906149c6565b90965094506000848611156119c85761193a6101208c01356119348b8861389c565b906138f1565b60405163a7d2087760e01b81529091506001600160a01b0384169063a7d208779061196f90879086908a908e90600401614de0565b604080518083038186803b15801561198657600080fd5b505afa15801561199a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119be91906149c6565b90975095506119d3565b506101208a01359450875b868110156119f35760405162461bcd60e51b815260040161075e9061502a565b86891115611a9e57600f546001600160a01b0316611a196101608d016101408e0161460a565b6001600160a01b0316148015611a3a5750611a3a60808c0160608d01614897565b15611a6857611a63611a546101a08d016101808e0161460a565b611a5e8b8a612a76565b61377c565b611a9e565b611a9e611a7d6101608d016101408e0161460a565b611a8f6101a08e016101808f0161460a565b611a998c8b612a76565b613921565b611aba611ab36101608d016101408e0161460a565b8b89613921565b5050506001600160a01b038716600090815260136020526040902054611ae590849061ffff16612a76565b92506000808215611af857849150611afb565b50835b600f546001600160a01b0316611b196101808c016101608d0161460a565b6001600160a01b0316148015611b3a5750611b3a60808b0160608c01614897565b15611bc55760405163022c0d9f60e01b81526001600160a01b038a169063022c0d9f90611b71908590859030908d906004016152e6565b600060405180830381600087803b158015611b8b57600080fd5b505af1158015611b9f573d6000803e3d6000fd5b50611bc09250611bba9150506101a08c016101808d0161460a565b8661377c565b611c3d565b886001600160a01b031663022c0d9f83838d610180016020810190611bea919061460a565b8b6040518563ffffffff1660e01b8152600401611c0a94939291906152e6565b600060405180830381600087803b158015611c2457600080fd5b505af1158015611c38573d6000803e3d6000fd5b505050505b50505050505050505050565b6010546001600160a01b031681565b6010546001600160a01b03163314611c825760405162461bcd60e51b815260040161075e90614f1c565b604051630fd1437d60e11b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc90631fa286fa906109fd90600090859060040161526c565b6000601454600014611ce05760405162461bcd60e51b815260040161075e90614e68565b60016014556011546001600160a01b03163314611d0f5760405162461bcd60e51b815260040161075e90614f1c565b604051621dd40d60e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc90621dd40d90610f75906000908690600d9060040161509e565b6001600160a01b031660009081526009602052604090205490565b6000601454600014611d895760405162461bcd60e51b815260040161075e90614e68565b6001601455604051638f0e6bef60e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc90638f0e6bef90610f75906000908690600d906004016150c2565b60136020526000908152604090205461ffff1681565b6010546001600160a01b03163314611e0b5760405162461bcd60e51b815260040161075e90614f1c565b6001600160a01b0382166000908152600d602052604090205415611e415760405162461bcd60e51b815260040161075e90614e4a565b6001600160a01b0382166000908152600e602052604090205460ff1615158115151415611e805760405162461bcd60e51b815260040161075e90614f3a565b6001600160a01b0382166000908152600e602052604090819020805460ff1916831515179055517fed243800dd924a6f05da349ad56411a9154d39d02c09c49db8faafc39663069690610eb49084908490614d9d565b6000610a3c8183613a6c565b6010546001600160a01b03163314611f0c5760405162461bcd60e51b815260040161075e90614f1c565b60405163153cc2fd60e31b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc9063a9e617e8906109fd90600090859060040161526c565b60145415611f665760405162461bcd60e51b815260040161075e90614e68565b60016014558060005a3360009081526012602052604081205491925090819060ff1680611fbd57506000805260126020527f7e7fa33969761a458e04f477e039a608702b4f924981d6653935a8319a08ad7b5460ff165b905060005b8481101561225457600254878783818110611fd957fe5b905061026002016000013511611fee5761224c565b600a6000888884818110611ffe57fe5b61026002919091013582525060208101919091526040016000205460ff16156120475761204287878381811061203057fe5b60009261026090910201359050613a75565b61224c565b73f5352c5035344d1ac36d2e4c2b6a237b13e82ffc632e548b5b600089898581811061206f57fe5b905061026002016040518363ffffffff1660e01b81526004016120939291906151ac565b60006040518083038186803b1580156120ab57600080fd5b505af41580156120bf573d6000803e3d6000fd5b5050505060008787838181106120d157fe5b905061026002016040013590504281106120eb5750612254565b82806120fb57506104b081014210155b6121175760405162461bcd60e51b815260040161075e90614f1c565b60019350600188888481811061212957fe5b9050610260020160200135141561215a5761215588888481811061214957fe5b90506102600201613aa0565b61224a565b600288888481811061216857fe5b905061026002016020013514156121945761215588888481811061218857fe5b90506102600201613cb7565b60058888848181106121a257fe5b905061026002016020013514806121cf575060068888848181106121c257fe5b9050610260020160200135145b156121ef576121558888848181106121e357fe5b90506102600201613de6565b60038888848181106121fd57fe5b9050610260020160200135148061222a5750600488888481811061221d57fe5b9050610260020160200135145b1561224a5761224a88888481811061223e57fe5b90506102600201613efb565b505b600101611fc2565b5081156122d05773f5352c5035344d1ac36d2e4c2b6a237b13e82ffc639db74df160006122825a8790612a76565b6040518363ffffffff1660e01b815260040161229f92919061526c565b60006040518083038186803b1580156122b757600080fd5b505af41580156122cb573d6000803e3d6000fd5b505050505b5050600060145550505050565b60006014546000146123015760405162461bcd60e51b815260040161075e90614e68565b600160145560405163758e99b360e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc9063758e99b390610f75906000908690600d9060040161509e565b6001600160a01b03166000908152600d602052604090205490565b6004546001600160a01b031690565b33301461238c5760405162461bcd60e51b815260040161075e90614f1c565b612397838383613921565b505050565b60006123a98184846129e7565b90505b92915050565b6010546001600160a01b031633146123dc5760405162461bcd60e51b815260040161075e90614f1c565b60405163b2456a0760e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc9063b2456a0790612418906000908690869060040161507f565b60006040518083038186803b15801561243057600080fd5b505af4158015610eed573d6000803e3d6000fd5b3330146124635760405162461bcd60e51b815260040161075e90614f1c565b426202a300826040013501101561248c5760405162461bcd60e51b815260040161075e90614fb2565b60006124a3610ac16101608401610140850161460a565b509050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156124e157600080fd5b505af11580156124f5573d6000803e3d6000fd5b5050505061250881828460e00135613921565b6000808061251c6080860160608701614897565b801561257a5750600f546001600160a01b03166125416101608701610140880161460a565b6001600160a01b0316148061257a5750600f546001600160a01b031661256f6101808701610160880161460a565b6001600160a01b0316145b156127005760007319f6bc0755fd4a465b3961fb335d6e55ab8b9eaa63cf58beed6125ad61016089016101408a0161460a565b6125bf6101808a016101608b0161460a565b600f5489906001600160a01b03166125df6101a08d016101808e0161460a565b60008052600960205260008051602061539c833981519152546040516001600160e01b031960e089901b16815261261e96959493929190600401614c75565b60806040518083038186803b15801561263657600080fd5b505af415801561264a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266e91906148b3565b919650945092509050806126fa57731441f0c929fdcb2d13d35d892ebca928a45b9d7963656621e0600d6126aa6101a08a016101808b0161460a565b876040518463ffffffff1660e01b81526004016126c99392919061507f565b60006040518083038186803b1580156126e157600080fd5b505af41580156126f5573d6000803e3d6000fd5b505050505b50612794565b6001600160a01b0384166389afcb446127216101a08801610180890161460a565b6040518263ffffffff1660e01b815260040161273d9190614c47565b6040805180830381600087803b15801561275657600080fd5b505af115801561276a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061278e91906149c6565b90925090505b84610100013582101580156127ae57508461012001358110155b610a295760405162461bcd60e51b815260040161075e90614ee0565b60015490565b3330146127ef5760405162461bcd60e51b815260040161075e90614f1c565b600f546001600160a01b0385811691161480156128095750805b1561293057604051632a359a6d60e21b8152600090731441f0c929fdcb2d13d35d892ebca928a45b9d799063a8d669b49061285190600d908990889087908b9060040161527a565b60206040518083038186803b15801561286957600080fd5b505af415801561287d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128a1919061498d565b600f54604051632e1a7d4d60e01b81529192506001600160a01b031690632e1a7d4d906128d29084906004016152c4565b600060405180830381600087803b1580156128ec57600080fd5b505af1158015612900573d6000803e3d6000fd5b5050600080525050600960205260008051602061539c8339815191525461292a9085908390613f45565b506129c9565b604051632a359a6d60e21b81526129c99085908590731441f0c929fdcb2d13d35d892ebca928a45b9d799063a8d669b49061297990600d9086908a90600090889060040161527a565b60206040518083038186803b15801561299157600080fd5b505af41580156129a5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a99919061498d565b50505050565b6000610a3c8183613fd7565b60025490565b60065490565b600083600101548311156129fd57506000612a6f565b6000838152600a8501602052604090205460ff1615612a1e57506005612a6f565b6000838152600c8501602052604090205460ff1615612a3f57506004612a6f565b6000838152600385016020526040902054612a5c57506003612a6f565b428210612a6b57506001612a6f565b5060025b9392505050565b60006123a983836040518060400160405280600481526020016329a6989960e11b815250613fe0565b808201828110156123ac576040805162461bcd60e51b81526020600480830191909152602482015263534d344560e01b604482015290519081900360640190fd5b600042612af560408501356301e13380612a9f565b109050600183602001351415612bda57600081612b2357612b1e6101a08501610180860161460a565b612b30565b6010546001600160a01b03165b9050612b7b81612b486101608701610140880161460a565b610100870135612b6061018089016101608a0161460a565b610120890135612b7660808b0160608c01614897565b614078565b612b975760405162461bcd60e51b815260040161075e90614ea4565b8215612bd457612bb881612bb360c087013560a088013561389c565b614202565b612bd45760405162461bcd60e51b815260040161075e90614f58565b50612d67565b600283602001351415612cb2576000612c10612bfe6101608601610140870161460a565b610ad36101808701610160880161460a565b509050600082612c3157612c2c6101a08601610180870161460a565b612c3e565b6010546001600160a01b03165b9050612c57828260e088013563064e6cbb60e51b614283565b612c735760405162461bcd60e51b815260040161075e90614ea4565b8315612cab57612c8f81612bb360c088013560a089013561389c565b612cab5760405162461bcd60e51b815260040161075e90614f58565b5050612d67565b600583602001351480612cc9575060068360200135145b15612d2c57600081612cec57612ce76101a08501610180860161460a565b612cf9565b6010546001600160a01b03165b9050612b7b612d106101608601610140870161460a565b82610100870135612d276080890160608a01614897565b6143a0565b600383602001351480612d43575060048360200135145b15612d6157600081612cec57612ce76101a08501610180860161460a565b50612d73565b612397600084356143ec565b5050565b600060025b6001600160a01b0383166000908152600b85016020526040902054600160ff9283161b16161515905092915050565b60048084015460405163e6a4390560e01b815260009283926001600160a01b03169163e6a4390591612de1918891889101614c5b565b60206040518083038186803b158015612df957600080fd5b505afa158015612e0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e319190614626565b91506001600160a01b038216612e595760405162461bcd60e51b815260040161075e90614f76565b826001600160a01b0316846001600160a01b0316119050935093915050565b6000808080731441f0c929fdcb2d13d35d892ebca928a45b9d7963a8d669b4600d612eab6101608a016101408b0161460a565b6101008a01356102208b0135612ec96101a08d016101808e0161460a565b6040518663ffffffff1660e01b8152600401612ee995949392919061527a565b60206040518083038186803b158015612f0157600080fd5b505af4158015612f15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f39919061498d565b90506000731441f0c929fdcb2d13d35d892ebca928a45b9d7963a8d669b4600d612f6b6101808b016101608c0161460a565b6101208b01356102408c0135612f896101a08e016101808f0161460a565b6040518663ffffffff1660e01b8152600401612fa995949392919061527a565b60206040518083038186803b158015612fc157600080fd5b505af4158015612fd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ff9919061498d565b9050856001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561303657600080fd5b505af115801561304a573d6000803e3d6000fd5b50505050730ec2323adafbebc6c80257c7359692bcceb0b3f1637a528bd2878961018001602081019061307d919061460a565b61308f6101608c016101408d0161460a565b6130a16101808d016101608e0161460a565b87876040518763ffffffff1660e01b81526004016130c496959493929190614cb0565b60606040518083038186803b1580156130dc57600080fd5b505af41580156130f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061311491906149e9565b9199909850909650945050505050565b60606000846001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561316157600080fd5b505afa158015613175573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131999190614626565b6001600160a01b0316636a9150fe85856040518363ffffffff1660e01b81526004016131c692919061526c565b60206040518083038186803b1580156131de57600080fd5b505afa1580156131f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613216919061498d565b90508060405160200161322991906152c4565b6040516020818303038152906040529150509392505050565b811561325357613253848684613921565b8015610a2957610a29838683613921565b60006003612d7c565b600080600080856001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401604080518083038186803b1580156132ab57600080fd5b505afa1580156132bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132e39190614943565b915091506132f760018861178d578261178f565b925050506000846001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561333657600080fd5b505afa15801561334a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061336e9190614626565b90506000856001600160a01b03166354cf2aeb6040518163ffffffff1660e01b815260040160206040518083038186803b1580156133ab57600080fd5b505afa1580156133bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e3919061498d565b90506000731441f0c929fdcb2d13d35d892ebca928a45b9d7963a8d669b4600d6134156101608d016101408e0161460a565b8c61010001358d61022001358e610180016020810190613435919061460a565b6040518663ffffffff1660e01b815260040161345595949392919061527a565b60206040518083038186803b15801561346d57600080fd5b505af4158015613481573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134a5919061498d565b905087613531576040516304a8fad760e31b81526001600160a01b03841690632547d6b8906134dc90859085908b90600401615313565b60206040518083038186803b1580156134f457600080fd5b505afa158015613508573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061352c919061498d565b6135b1565b60405163c4109d2560e01b81526001600160a01b0384169063c4109d259061356190859085908b90600401615313565b60206040518083038186803b15801561357957600080fd5b505afa15801561358d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b1919061498d565b9450600084861115613701576135d6866135d06101208d01358861389c565b90614400565b60405163a7d2087760e01b815290915082906001600160a01b0386169063a7d208779061360d908d9088908b908e90600401614de0565b604080518083038186803b15801561362457600080fd5b505afa158015613638573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061365c91906149c6565b600f549098509093506001600160a01b03166136806101608d016101408e0161460a565b6001600160a01b03161480156136a157506136a160808c0160608d01614897565b156136ca576136c56136bb6101a08d016101808e0161460a565b611a5e8386612a76565b6136fb565b6136fb6136df6101608d016101408e0161460a565b6136f16101a08e016101808f0161460a565b611a998487612a76565b50613709565b506101208901355b6001600160a01b03881660009081526013602052604090205461373190879061ffff16612a76565b9550808610156137535760405162461bcd60e51b815260040161075e90614efe565b61376f6137686101608c016101408d0161460a565b8984613921565b5050505050949350505050565b600f54604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906137ac9084906004016152c4565b600060405180830381600087803b1580156137c657600080fd5b505af11580156137da573d6000803e3d6000fd5b50506000808052600960205260008051602061539c833981519152546040519193506001600160a01b038616925090849061381490614c44565b600060405180830381858888f193505050503d8060008114613852576040519150601f19603f3d011682016040523d82523d6000602084013e613857565b606091505b50509050806123975760405163032b310f60e51b8152731441f0c929fdcb2d13d35d892ebca928a45b9d799063656621e09061152e90600d908790879060040161507f565b60008115806138b7575050808202828282816138b457fe5b04145b6123ac576040805162461bcd60e51b81526020600480830191909152602482015263534d324160e01b604482015290519081900360640190fd5b60006138fd8383614400565b9050613909828261389c565b83146123ac5761391a816001612a9f565b90506123ac565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b6020831061399d5780518252601f19909201916020918201910161397e565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146139ff576040519150601f19603f3d011682016040523d82523d6000602084013e613a04565b606091505b5091509150818015613a32575080511580613a325750808060200190516020811015613a2f57600080fd5b50515b610a29576040805162461bcd60e51b815260206004808301919091526024820152635448303560e01b604482015290519081900360640190fd5b60006001612d7c565b600282018054600101908190558114612d735760405162461bcd60e51b815260040161075e90614fee565b60005a9050613ab160008335613a75565b60008030613b35613b2a600984613ad06101808a016101608b0161460a565b6001600160a01b0316815260208101919091526040016000908120549061083b90600990613b066101608c016101408d0161460a565b6001600160a01b03168152602081019190915260400160002054620108dc90612a9f565b60a087013590612a76565b60405163303a892b60e01b90613b4f9088906024016152a6565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613b8d9190614c28565b60006040518083038160008787f1925050503d8060008114613bcb576040519150601f19603f3d011682016040523d82523d6000602084013e613bd0565b606091505b509092509050600182613c3557613c32613bf26101a08701610180880161460a565b613c046101608801610140890161460a565b610100880135613c1c6101808a016101608b0161460a565b6101208a0135612b7660808c0160608d01614897565b90505b613c3e81614450565b600080613c6660a088013560c089013588613c616101a08c016101808d0161460a565b614471565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613ca693929190614e11565b60405180910390a350505050505050565b60005a9050613cc860008335613a75565b60008030613cde613b2a620108dc61d6d8612a9f565b60405163714abbf760e11b90613cf89088906024016152a6565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613d369190614c28565b60006040518083038160008787f1925050503d8060008114613d74576040519150601f19603f3d011682016040523d82523d6000602084013e613d79565b606091505b509092509050600182613c35576000613daf613d9d6101608801610140890161460a565b610ad361018089016101608a0161460a565b509050613dda81613dc86101a089016101808a0161460a565b60e089013563064e6cbb60e51b614283565b915050613c3e81614450565b60005a9050613df760008335613a75565b60008030613e16613b2a600984613b066101608a016101408b0161460a565b604051631a3d8e8d60e21b90613e309088906024016152a6565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613e6e9190614c28565b60006040518083038160008787f1925050503d8060008114613eac576040519150601f19603f3d011682016040523d82523d6000602084013e613eb1565b606091505b509092509050600182613c3557613c32613ed36101608701610140880161460a565b613ee56101a08801610180890161460a565b610100880135612d2760808a0160608b01614897565b60005a9050613f0c60008335613a75565b60008030613f2b613b2a600984613b066101608a016101408b0161460a565b6040516389e707ad60e01b90613e309088906024016152a6565b6040516000906001600160a01b038516908390859084818181858888f193505050503d8060008114613f93576040519150601f19603f3d011682016040523d82523d6000602084013e613f98565b606091505b50509050806129c9576040805162461bcd60e51b815260206004808301919091526024820152632a2419a360e11b604482015290519081900360640190fd5b60006004612d7c565b81830381848211156140705760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561403557818101518382015260200161401d565b50505050905090810190601f1680156140625780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509392505050565b6001600160a01b0383811660009081526009602052604080822054928816825281205490918291829130916140ac91612a9f565b604051633ed76f1760e01b906140d0908d908d908d908d908d908d90602401614cea565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161410e9190614c28565b60006040518083038160008787f1925050503d806000811461414c576040519150601f19603f3d011682016040523d82523d6000602084013e614151565b606091505b5091509150816141f657876001600160a01b0316896001600160a01b03167f786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b21159289846040516141a09291906152cd565b60405180910390a3856001600160a01b0316896001600160a01b03167f786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b21159287846040516141ed9291906152cd565b60405180910390a35b50979650505050505050565b600081614211575060016123ac565b60008052600960205260008051602061539c833981519152546142379084908490614501565b9050801515836001600160a01b03167fdbef2fc26e7694e7a1c5a4801b1ad144136d149cf76f310a780689b4087f0ffe8460405161427591906152c4565b60405180910390a392915050565b60008261429257506001614398565b600080306001600160a01b031661d6d88589898960006040516024016142bb9493929190614d24565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516142f99190614c28565b60006040518083038160008787f1925050503d8060008114614337576040519150601f19603f3d011682016040523d82523d6000602084013e61433c565b606091505b50915091508161439457866001600160a01b0316866001600160a01b03167f786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b211592878460405161438b9291906152cd565b60405180910390a35b5090505b949350505050565b6000826143af57506001614398565b6001600160a01b0385166000908152600960205260408082205490518291309163e5b1be6560e01b906142bb908b908b908b908b90602401614d24565b600090815260039091016020526040812055565b600080821161443f576040805162461bcd60e51b81526020600480830191909152602482015263534d343360e01b604482015290519081900360640190fd5b81838161444857fe5b049392505050565b806144645761445f600061455f565b61446e565b61446e6000614582565b50565b6000808061447f878761389c565b90506144926193ac61083b5a8890612a76565b925060006144b7826144b26000600601548761389c90919063ffffffff16565b61459b565b90506144c38282612a76565b92506144cf3382614202565b6144eb5760405162461bcd60e51b815260040161075e90614f58565b6144f58584614202565b50505094509492505050565b6040516000906001600160a01b038516908390859084818181858888f193505050503d806000811461454f576040519150601f19603f3d011682016040523d82523d6000602084013e614554565b606091505b509095945050505050565b60028101546000908152600c90910160205260409020805460ff19166001179055565b6002810154600090815260039091016020526040812055565b60008183106145aa57816123a9565b5090919050565b8035610a3f81615378565b8035610a3f8161538d565b600061010082840312156145d9578081fd5b50919050565b80516001600160701b0381168114610a3f57600080fd5b803563ffffffff81168114610a3f57600080fd5b60006020828403121561461b578081fd5b8135612a6f81615378565b600060208284031215614637578081fd5b8151612a6f81615378565b600080600060608486031215614656578182fd5b833561466181615378565b9250602084013561467181615378565b929592945050506040919091013590565b60008060008060008060c0878903121561469a578182fd5b86356146a581615378565b955060208701356146b581615378565b94506040870135935060608701356146cc81615378565b92506080870135915060a08701356146e38161538d565b809150509295509295509295565b60008060008060808587031215614706578384fd5b843561471181615378565b9350602085013561472181615378565b92506040850135915060608501356147388161538d565b939692955090935050565b60008060408385031215614755578182fd5b823561476081615378565b915060208301356147708161538d565b809150509250929050565b60008060006060848603121561478f578283fd5b833561479a81615378565b92506020840135600581106147ad578283fd5b915060408401356147bd8161538d565b809150509250925092565b600080604083850312156147da578182fd5b82356147e581615378565b9150602083013561ffff81168114614770578182fd5b6000806040838503121561480d578081fd5b823561481881615378565b946020939093013593505050565b60008060208385031215614838578182fd5b823567ffffffffffffffff8082111561484f578384fd5b818501915085601f830112614862578384fd5b813581811115614870578485fd5b86602061026083028501011115614885578485fd5b60209290920196919550909350505050565b6000602082840312156148a8578081fd5b8135612a6f8161538d565b600080600080608085870312156148c8578182fd5b84516148d38161538d565b60208601516040870151606090970151919890975090945092505050565b60006101008284031215614903578081fd5b6123a983836145c7565b600061016082840312156145d9578081fd5b600061026082840312156145d9578081fd5b600061012082840312156145d9578081fd5b60008060408385031215614955578182fd5b61495e836145df565b915061496c602084016145df565b90509250929050565b600060208284031215614986578081fd5b5035919050565b60006020828403121561499e578081fd5b5051919050565b600080604083850312156149b7578182fd5b50508035926020909101359150565b600080604083850312156149d8578182fd5b505080516020909101519092909150565b6000806000606084860312156149fd578081fd5b8351925060208401519150604084015190509250925092565b600060208284031215614a27578081fd5b6123a9826145f6565b6001600160a01b03169052565b15159052565b60008151808452614a5b81602086016020860161534c565b601f01601f19169290920160200192915050565b8035614a7a81615378565b6001600160a01b039081168352602082013590614a9682615378565b16602083015260408181013590830152606080820135908301526080810135614abe8161538d565b1515608083015260a0810135614ad381615378565b614ae060a0840182614a30565b5060c081013560c0830152614af760e082016145f6565b61239760e0840182614c1e565b803582526020810135602083015260408101356040830152614b28606082016145bc565b614b356060840182614a3d565b506080810135608083015260a081013560a083015260c081013560c083015260e081013560e0830152610100808201358184015250610120808201358184015250610140614b848183016145b1565b614b9082850182614a30565b5050610160614ba08183016145b1565b614bac82850182614a30565b5050610180614bbc8183016145b1565b614bc882850182614a30565b50506101a081810135908301526101c080820135908301526101e0614bee8183016145bc565b614bfa82850182614a3d565b50506102008181013590830152610220808201359083015261024090810135910152565b63ffffffff169052565b60008251614c3a81846020870161534c565b9190910192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039687168152948616602086015292851660408501529084166060840152909216608082015260a081019190915260c00190565b6001600160a01b0396871681529486166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b6001600160a01b0396871681529486166020860152604085019390935293166060830152608082019290925290151560a082015260c00190565b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b6001600160a01b03878116825286166020820152604081018590526060810184905261ffff8316608082015260c060a08201819052600090614d9190830184614a43565b98975050505050505050565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b0392909216825261ffff16602082015260400190565b901515815260200190565b6000851515825284602083015283604083015260806060830152614e076080830184614a43565b9695505050505050565b600060608252614e246060830186614a43565b60208301949094525060400152919050565b6020810160068310614e4457fe5b91905290565b60208082526004908201526315110dcd60e21b604082015260600190565b6020808252600490820152632a22181b60e11b604082015260600190565b6020808252600490820152635444314360e01b604082015260600190565b60208082526004908201526315110c4d60e21b604082015260600190565b6020808252600490820152635444323160e01b604082015260600190565b6020808252600490820152635444303360e01b604082015260600190565b6020808252600490820152635444333760e01b604082015260600190565b6020808252600490820152630544430360e41b604082015260600190565b6020808252600490820152635444303160e01b604082015260600190565b6020808252600490820152630544434360e41b604082015260600190565b6020808252600490820152634f53313760e01b604082015260600190565b60208082526004908201526315110d4d60e21b604082015260600190565b60208082526004908201526315110c0d60e21b604082015260600190565b6020808252600490820152632a221a9960e11b604082015260600190565b60208082526004908201526327a99b9960e11b604082015260600190565b6020808252600490820152632a22181960e11b604082015260600190565b6020808252600490820152630a88860760e31b604082015260600190565b8481526001600160a01b0384166020820152608081016005841061506857fe5b836040830152821515606083015295945050505050565b9283526001600160a01b03919091166020830152604082015260600190565b83815261014081016150b36020830185614a6f565b82610120830152949350505050565b8381526101a081016150df602083016150da866145b1565b614a30565b6150eb602085016145b1565b6150f86040840182614a30565b506040840135606083015260608401356080830152608084013560a083015260a084013560c083015261512d60c085016145bc565b61513a60e0840182614a3d565b5061514760e085016145bc565b61010061515681850183614a3d565b6151618187016145b1565b91505061012061517381850183614a30565b610140915080860135828501525061518c8186016145f6565b905061519c610160840182614c1e565b5082610180830152949350505050565b8281526102808101612a6f6020830184614b04565b82815261014081016151d9602083016150da856145b1565b6151e5602084016145b1565b6151f26040840182614a30565b506040830135606083015260608301356080830152608083013560a083015261521d60a084016145bc565b61522a60c0840182614a3d565b5061523760c084016145b1565b61524460e0840182614a30565b5061010060e08401358184015261525c8185016145f6565b9050614070610120840182614c1e565b918252602082015260400190565b9485526001600160a01b0393841660208601526040850192909252606084015216608082015260a00190565b61026081016123ac8284614b04565b61ffff91909116815260200190565b90815260200190565b6000838252604060208301526143986040830184614a43565b600085825284602083015260018060a01b038416604083015260806060830152614e076080830184614a43565b6000848252836020830152606060408301526153326060830184614a43565b95945050505050565b63ffffffff91909116815260200190565b60005b8381101561536757818101518382015260200161534f565b838111156129c95750506000910152565b6001600160a01b038116811461446e57600080fd5b801515811461446e57600080fdfeec8156718a8372b1db44bb411437d0870f3e3790d4a08526d024ce1b0b668f6ba26469706673582212208aa322a455c1087b5f4e71b05ad4ffd280aef00d7c7ca850d097bde81bbccf0264736f6c63430007060033000000000000000000000000c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c6000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000003a1d749fa4a9e650fce844ff1c58c5faf7e2a9d1
Deployed Bytecode
0x6080604052600436106102975760003560e01c80638406c0791161015a578063ba4d5312116100c1578063e29577ee1161007a578063e29577ee146106b9578063e30a4993146106cc578063e5b1be65146106e1578063e5e7988e146106f4578063e6a0cc9414610714578063fe173b97146107295761029e565b8063ba4d53121461061e578063bf6b874e14610631578063c45a015514610651578063c9cd976014610666578063ceb0981f14610679578063d22e9242146106a65761029e565b80639d08ebb5116101135780639d08ebb514610585578063a70885c114610598578063ab13d9bd146105c5578063af482b58146105d8578063b32ac936146105f8578063b5540b2b1461060b5761029e565b80638406c0791461050257806389e707ad146105175780638da5cb5b1461052a578063945317131461053f578063953556e2146105525780639718f627146105655761029e565b80635051349a116101fe5780636a42b8f8116101b75780636a42b8f8146104725780636de3c67c1461048757806370190d4c1461049c57806377632ec2146104bc578063793ab297146104dc5780637f6a1caf146104ef5761029e565b80635051349a146103ef578063576b332b1461040f57806357a62a4f146104225780635e45da23146104375780636548e9bc1461044c57806368f63a341461045f5761029e565b8063303a892b11610250578063303a892b14610354578063342aa8b5146103675780633bbac5791461037a5780633ed76f171461039a5780633fc8cef3146103ad5780634c016016146103cf5761029e565b806302241c70146102a357806310348665146102c557806313af4035146102d85780631776834a146102eb57806320a68fab146102fe5780632c391c7b146103345761029e565b3661029e57005b600080fd5b3480156102af57600080fd5b506102c36102be36600461491f565b61073e565b005b6102c36102d3366004614a16565b61088f565b6102c36102e636600461460a565b6108fe565b6102c36102f9366004614975565b610999565b34801561030a57600080fd5b5061031e61031936600461460a565b610a30565b60405161032b9190614dd5565b60405180910390f35b34801561034057600080fd5b5061031e61034f36600461460a565b610a44565b6102c361036236600461491f565b610a62565b6102c3610375366004614743565b610e34565b34801561038657600080fd5b5061031e61039536600461460a565b610ec0565b6102c36103a8366004614682565b610ed5565b3480156103b957600080fd5b506103c2610ef5565b60405161032b9190614c47565b3480156103db57600080fd5b5061031e6103ea36600461460a565b610f04565b6104026103fd3660046148f1565b610f10565b60405161032b91906152c4565b61040261041d366004614931565b610fb3565b34801561042e57600080fd5b50610402611016565b34801561044357600080fd5b5061040261101c565b6102c361045a36600461460a565b611022565b6102c361046d36600461491f565b6110eb565b34801561047e57600080fd5b50610402611332565b34801561049357600080fd5b50610402611338565b3480156104a857600080fd5b506102c36104b736600461491f565b61133e565b3480156104c857600080fd5b5061031e6104d7366004614975565b611409565b6102c36104ea3660046147c8565b61141e565b6102c36104fd36600461477b565b6114c6565b34801561050e57600080fd5b506103c261155a565b6102c361052536600461491f565b611569565b34801561053657600080fd5b506103c2611c49565b6102c361054d366004614975565b611c58565b6104026105603660046148f1565b611cbc565b34801561057157600080fd5b5061040261058036600461460a565b611d4a565b61040261059336600461490d565b611d65565b3480156105a457600080fd5b506105b86105b336600461460a565b611dcb565b60405161032b91906152b5565b6102c36105d3366004614743565b611de1565b3480156105e457600080fd5b5061031e6105f336600461460a565b611ed6565b6102c3610606366004614975565b611ee2565b6102c3610619366004614826565b611f46565b61040261062c3660046148f1565b6122dd565b34801561063d57600080fd5b5061040261064c36600461460a565b612343565b34801561065d57600080fd5b506103c261235e565b6102c3610674366004614642565b61236d565b34801561068557600080fd5b506106996106943660046149a5565b61239c565b60405161032b9190614e36565b6102c36106b43660046147fb565b6123b2565b6102c36106c736600461491f565b612444565b3480156106d857600080fd5b506104026127ca565b6102c36106ef3660046146f1565b6127d0565b34801561070057600080fd5b5061031e61070f36600461460a565b6129cf565b34801561072057600080fd5b506104026129db565b34801561073557600080fd5b506104026129e1565b601454156107675760405162461bcd60e51b815260040161075e90614e68565b60405180910390fd5b6001601455604051632e548b5b60e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc90632e548b5b906107a69060009085906004016151ac565b60006040518083038186803b1580156107be57600080fd5b505af41580156107d2573d6000803e3d6000fd5b50600292506107df915050565b6107f06000833560408501356129e7565b60058111156107fb57fe5b146108185760405162461bcd60e51b815260040161075e90614fd0565b426108416201518061083b60008001548560400135612a7690919063ffffffff16565b90612a9f565b1061085e5760405162461bcd60e51b815260040161075e90614e86565b80356000908152600a60205260409020805460ff19166001908117909155610887908290612ae0565b506000601455565b6010546001600160a01b031633146108b95760405162461bcd60e51b815260040161075e90614f1c565b63ffffffff81166000556040517f63e09f16584208fba1fc7ff64c62b00f07bec177c0d97ca6689891b1e77a35c7906108f390839061533b565b60405180910390a150565b6010546001600160a01b031633146109285760405162461bcd60e51b815260040161075e90614f1c565b6001600160a01b03811661094e5760405162461bcd60e51b815260040161075e9061500c565b601080546001600160a01b0319166001600160a01b0383161790556040517f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe2906108f3908390614c47565b6010546001600160a01b031633146109c35760405162461bcd60e51b815260040161075e90614f1c565b604051636702eca360e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc90636702eca3906109fd90600090859060040161526c565b60006040518083038186803b158015610a1557600080fd5b505af4158015610a29573d6000803e3d6000fd5b5050505050565b6000610a3c8183612d77565b90505b919050565b6001600160a01b03166000908152600e602052604090205460ff1690565b333014610a815760405162461bcd60e51b815260040161075e90614f1c565b426202a3008260400135011015610aaa5760405162461bcd60e51b815260040161075e90614fb2565b6000610adc610ac16101608401610140850161460a565b610ad36101808501610160860161460a565b60009190612dab565b5090506000806000610aee8585612e78565b91945092509050610b0761020086016101e08701614897565b8015610b1257508015155b15610d16576000610b2d858761020001358860800135613124565b90508315801590610b3e5750816001145b15610c24576000730ec2323adafbebc6c80257c7359692bcceb0b3f163d0b0a9bc87610b726101608b016101408c0161460a565b6001600160a01b038a16600090815260136020526040908190205490516001600160e01b031960e086901b168152610bbe9392918b916101a08f01359161ffff16908a90600401614d4d565b604080518083038186803b158015610bd557600080fd5b505af4158015610be9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0d91906149c6565b9095509050610c1c8482612a9f565b935050610d14565b8215801590610c335750816002145b15610d14576000730ec2323adafbebc6c80257c7359692bcceb0b3f163adf5f8f387610c676101808b016101608c0161460a565b6001600160a01b038a16600090815260136020526040908190205490516001600160e01b031960e086901b168152610cb39392918a916101c08f01359161ffff16908a90600401614d4d565b604080518083038186803b158015610cca57600080fd5b505af4158015610cde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d0291906149c6565b94509050610d108582612a9f565b9450505b505b8215801590610d2457508115155b15610df457730ec2323adafbebc6c80257c7359692bcceb0b3f1637a528bd285610d566101a089016101808a0161460a565b610d686101608a016101408b0161460a565b610d7a6101808b016101608c0161460a565b88886040518763ffffffff1660e01b8152600401610d9d96959493929190614cb0565b60606040518083038186803b158015610db557600080fd5b505af4158015610dc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ded91906149e9565b5090935091505b610a29610e096101a08701610180880161460a565b610e1b6101608801610140890161460a565b610e2d61018089016101608a0161460a565b8686613242565b6010546001600160a01b03163314610e5e5760405162461bcd60e51b815260040161075e90614f1c565b6001600160a01b03821660009081526012602052604090819020805460ff1916831515179055517f70af441dbb427737e6a5ef2cf5b664321011765ce1d19ce4a69cd024e69d4f2f90610eb49084908490614d9d565b60405180910390a15050565b60126020526000908152604090205460ff1681565b610ee1858786846127d0565b610eed838784846127d0565b505050505050565b600f546001600160a01b031690565b6000610a3c8183613264565b6000601454600014610f345760405162461bcd60e51b815260040161075e90614e68565b600160145560405162c44ff160e31b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc906306227f8890610f75906000908690600d9060040161509e565b60006040518083038186803b158015610f8d57600080fd5b505af4158015610fa1573d6000803e3d6000fd5b50506001546000601455949350505050565b6000601454600014610fd75760405162461bcd60e51b815260040161075e90614e68565b6001601455604051636587992160e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc90636587992190610f759060009086906004016151c1565b60085490565b60055490565b6010546001600160a01b0316331461104c5760405162461bcd60e51b815260040161075e90614f1c565b6011546001600160a01b038281169116141561107a5760405162461bcd60e51b815260040161075e90614f3a565b6001600160a01b0381166110a05760405162461bcd60e51b815260040161075e9061500c565b601180546001600160a01b0319166001600160a01b0383161790556040517fb7041340e0c2a075059bf0488a71c767724be15dae8e737f8460007325e8d857906108f3908390614c47565b33301461110a5760405162461bcd60e51b815260040161075e90614f1c565b426202a30082604001350110156111335760405162461bcd60e51b815260040161075e90614fb2565b600061114a610ac16101608401610140850161460a565b509050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561118857600080fd5b505af115801561119c573d6000803e3d6000fd5b5050505060006111b6828461020001358560800135613124565b9050602083013560061460006111ce8583868661326d565b9050600080836111e0576000836111e4565b8260005b600f5491935091506001600160a01b031661120761018089016101608a0161460a565b6001600160a01b031614801561122857506112286080880160608901614897565b156112b35760405163022c0d9f60e01b81526001600160a01b0387169063022c0d9f9061125f908590859030908b906004016152e6565b600060405180830381600087803b15801561127957600080fd5b505af115801561128d573d6000803e3d6000fd5b506112ae92506112a89150506101a089016101808a0161460a565b8461377c565b611329565b6001600160a01b03861663022c0d9f83836112d66101a08c016101808d0161460a565b896040518563ffffffff1660e01b81526004016112f694939291906152e6565b600060405180830381600087803b15801561131057600080fd5b505af1158015611324573d6000803e3d6000fd5b505050505b50505050505050565b60005490565b60075490565b6014541561135e5760405162461bcd60e51b815260040161075e90614e68565b6001601455604051632e548b5b60e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc90632e548b5b9061139d9060009085906004016151ac565b60006040518083038186803b1580156113b557600080fd5b505af41580156113c9573d6000803e3d6000fd5b50505081356000908152600c602052604090205460ff1690506113fe5760405162461bcd60e51b815260040161075e90614ec2565b610887816000612ae0565b6000908152600a602052604090205460ff1690565b6010546001600160a01b031633146114485760405162461bcd60e51b815260040161075e90614f1c565b600a61ffff8216111561146d5760405162461bcd60e51b815260040161075e90614f94565b6001600160a01b03821660009081526013602052604090819020805461ffff191661ffff8416179055517f6b4044e33be5af8fcdb7449c49137010eede3c8c06d5d08067151a7ace17266d90610eb49084908490614db8565b6010546001600160a01b031633146114f05760405162461bcd60e51b815260040161075e90614f1c565b60405163146bce4f60e31b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc9063a35e72789061152e90600090879087908790600401615048565b60006040518083038186803b15801561154657600080fd5b505af4158015611329573d6000803e3d6000fd5b6011546001600160a01b031681565b3330146115885760405162461bcd60e51b815260040161075e90614f1c565b426202a30082604001350110156115b15760405162461bcd60e51b815260040161075e90614fb2565b60006115c8610ac16101608401610140850161460a565b5090506000731441f0c929fdcb2d13d35d892ebca928a45b9d7963a8d669b4600d6115fb6101608701610140880161460a565b6101008701356102208801356116196101a08a016101808b0161460a565b6040518663ffffffff1660e01b815260040161163995949392919061527a565b60206040518083038186803b15801561165157600080fd5b505af4158015611665573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611689919061498d565b9050816001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156116c657600080fd5b505af11580156116da573d6000803e3d6000fd5b5050505060006116f4838561020001358660800135613124565b905060008060008060048860200135149050600080886001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401604080518083038186803b15801561174157600080fd5b505afa158015611755573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117799190614943565b9150915061179e60018461178d578261178f565b835b6001600160701b031690612a76565b935050506000876001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b1580156117dd57600080fd5b505afa1580156117f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118159190614626565b90506000886001600160a01b03166354cf2aeb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561185257600080fd5b505afa158015611866573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188a919061498d565b9050816001600160a01b031663daab4b6e84838d61012001358b6040518563ffffffff1660e01b81526004016118c39493929190614de0565b604080518083038186803b1580156118da57600080fd5b505afa1580156118ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191291906149c6565b90965094506000848611156119c85761193a6101208c01356119348b8861389c565b906138f1565b60405163a7d2087760e01b81529091506001600160a01b0384169063a7d208779061196f90879086908a908e90600401614de0565b604080518083038186803b15801561198657600080fd5b505afa15801561199a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119be91906149c6565b90975095506119d3565b506101208a01359450875b868110156119f35760405162461bcd60e51b815260040161075e9061502a565b86891115611a9e57600f546001600160a01b0316611a196101608d016101408e0161460a565b6001600160a01b0316148015611a3a5750611a3a60808c0160608d01614897565b15611a6857611a63611a546101a08d016101808e0161460a565b611a5e8b8a612a76565b61377c565b611a9e565b611a9e611a7d6101608d016101408e0161460a565b611a8f6101a08e016101808f0161460a565b611a998c8b612a76565b613921565b611aba611ab36101608d016101408e0161460a565b8b89613921565b5050506001600160a01b038716600090815260136020526040902054611ae590849061ffff16612a76565b92506000808215611af857849150611afb565b50835b600f546001600160a01b0316611b196101808c016101608d0161460a565b6001600160a01b0316148015611b3a5750611b3a60808b0160608c01614897565b15611bc55760405163022c0d9f60e01b81526001600160a01b038a169063022c0d9f90611b71908590859030908d906004016152e6565b600060405180830381600087803b158015611b8b57600080fd5b505af1158015611b9f573d6000803e3d6000fd5b50611bc09250611bba9150506101a08c016101808d0161460a565b8661377c565b611c3d565b886001600160a01b031663022c0d9f83838d610180016020810190611bea919061460a565b8b6040518563ffffffff1660e01b8152600401611c0a94939291906152e6565b600060405180830381600087803b158015611c2457600080fd5b505af1158015611c38573d6000803e3d6000fd5b505050505b50505050505050505050565b6010546001600160a01b031681565b6010546001600160a01b03163314611c825760405162461bcd60e51b815260040161075e90614f1c565b604051630fd1437d60e11b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc90631fa286fa906109fd90600090859060040161526c565b6000601454600014611ce05760405162461bcd60e51b815260040161075e90614e68565b60016014556011546001600160a01b03163314611d0f5760405162461bcd60e51b815260040161075e90614f1c565b604051621dd40d60e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc90621dd40d90610f75906000908690600d9060040161509e565b6001600160a01b031660009081526009602052604090205490565b6000601454600014611d895760405162461bcd60e51b815260040161075e90614e68565b6001601455604051638f0e6bef60e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc90638f0e6bef90610f75906000908690600d906004016150c2565b60136020526000908152604090205461ffff1681565b6010546001600160a01b03163314611e0b5760405162461bcd60e51b815260040161075e90614f1c565b6001600160a01b0382166000908152600d602052604090205415611e415760405162461bcd60e51b815260040161075e90614e4a565b6001600160a01b0382166000908152600e602052604090205460ff1615158115151415611e805760405162461bcd60e51b815260040161075e90614f3a565b6001600160a01b0382166000908152600e602052604090819020805460ff1916831515179055517fed243800dd924a6f05da349ad56411a9154d39d02c09c49db8faafc39663069690610eb49084908490614d9d565b6000610a3c8183613a6c565b6010546001600160a01b03163314611f0c5760405162461bcd60e51b815260040161075e90614f1c565b60405163153cc2fd60e31b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc9063a9e617e8906109fd90600090859060040161526c565b60145415611f665760405162461bcd60e51b815260040161075e90614e68565b60016014558060005a3360009081526012602052604081205491925090819060ff1680611fbd57506000805260126020527f7e7fa33969761a458e04f477e039a608702b4f924981d6653935a8319a08ad7b5460ff165b905060005b8481101561225457600254878783818110611fd957fe5b905061026002016000013511611fee5761224c565b600a6000888884818110611ffe57fe5b61026002919091013582525060208101919091526040016000205460ff16156120475761204287878381811061203057fe5b60009261026090910201359050613a75565b61224c565b73f5352c5035344d1ac36d2e4c2b6a237b13e82ffc632e548b5b600089898581811061206f57fe5b905061026002016040518363ffffffff1660e01b81526004016120939291906151ac565b60006040518083038186803b1580156120ab57600080fd5b505af41580156120bf573d6000803e3d6000fd5b5050505060008787838181106120d157fe5b905061026002016040013590504281106120eb5750612254565b82806120fb57506104b081014210155b6121175760405162461bcd60e51b815260040161075e90614f1c565b60019350600188888481811061212957fe5b9050610260020160200135141561215a5761215588888481811061214957fe5b90506102600201613aa0565b61224a565b600288888481811061216857fe5b905061026002016020013514156121945761215588888481811061218857fe5b90506102600201613cb7565b60058888848181106121a257fe5b905061026002016020013514806121cf575060068888848181106121c257fe5b9050610260020160200135145b156121ef576121558888848181106121e357fe5b90506102600201613de6565b60038888848181106121fd57fe5b9050610260020160200135148061222a5750600488888481811061221d57fe5b9050610260020160200135145b1561224a5761224a88888481811061223e57fe5b90506102600201613efb565b505b600101611fc2565b5081156122d05773f5352c5035344d1ac36d2e4c2b6a237b13e82ffc639db74df160006122825a8790612a76565b6040518363ffffffff1660e01b815260040161229f92919061526c565b60006040518083038186803b1580156122b757600080fd5b505af41580156122cb573d6000803e3d6000fd5b505050505b5050600060145550505050565b60006014546000146123015760405162461bcd60e51b815260040161075e90614e68565b600160145560405163758e99b360e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc9063758e99b390610f75906000908690600d9060040161509e565b6001600160a01b03166000908152600d602052604090205490565b6004546001600160a01b031690565b33301461238c5760405162461bcd60e51b815260040161075e90614f1c565b612397838383613921565b505050565b60006123a98184846129e7565b90505b92915050565b6010546001600160a01b031633146123dc5760405162461bcd60e51b815260040161075e90614f1c565b60405163b2456a0760e01b815273f5352c5035344d1ac36d2e4c2b6a237b13e82ffc9063b2456a0790612418906000908690869060040161507f565b60006040518083038186803b15801561243057600080fd5b505af4158015610eed573d6000803e3d6000fd5b3330146124635760405162461bcd60e51b815260040161075e90614f1c565b426202a300826040013501101561248c5760405162461bcd60e51b815260040161075e90614fb2565b60006124a3610ac16101608401610140850161460a565b509050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156124e157600080fd5b505af11580156124f5573d6000803e3d6000fd5b5050505061250881828460e00135613921565b6000808061251c6080860160608701614897565b801561257a5750600f546001600160a01b03166125416101608701610140880161460a565b6001600160a01b0316148061257a5750600f546001600160a01b031661256f6101808701610160880161460a565b6001600160a01b0316145b156127005760007319f6bc0755fd4a465b3961fb335d6e55ab8b9eaa63cf58beed6125ad61016089016101408a0161460a565b6125bf6101808a016101608b0161460a565b600f5489906001600160a01b03166125df6101a08d016101808e0161460a565b60008052600960205260008051602061539c833981519152546040516001600160e01b031960e089901b16815261261e96959493929190600401614c75565b60806040518083038186803b15801561263657600080fd5b505af415801561264a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266e91906148b3565b919650945092509050806126fa57731441f0c929fdcb2d13d35d892ebca928a45b9d7963656621e0600d6126aa6101a08a016101808b0161460a565b876040518463ffffffff1660e01b81526004016126c99392919061507f565b60006040518083038186803b1580156126e157600080fd5b505af41580156126f5573d6000803e3d6000fd5b505050505b50612794565b6001600160a01b0384166389afcb446127216101a08801610180890161460a565b6040518263ffffffff1660e01b815260040161273d9190614c47565b6040805180830381600087803b15801561275657600080fd5b505af115801561276a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061278e91906149c6565b90925090505b84610100013582101580156127ae57508461012001358110155b610a295760405162461bcd60e51b815260040161075e90614ee0565b60015490565b3330146127ef5760405162461bcd60e51b815260040161075e90614f1c565b600f546001600160a01b0385811691161480156128095750805b1561293057604051632a359a6d60e21b8152600090731441f0c929fdcb2d13d35d892ebca928a45b9d799063a8d669b49061285190600d908990889087908b9060040161527a565b60206040518083038186803b15801561286957600080fd5b505af415801561287d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128a1919061498d565b600f54604051632e1a7d4d60e01b81529192506001600160a01b031690632e1a7d4d906128d29084906004016152c4565b600060405180830381600087803b1580156128ec57600080fd5b505af1158015612900573d6000803e3d6000fd5b5050600080525050600960205260008051602061539c8339815191525461292a9085908390613f45565b506129c9565b604051632a359a6d60e21b81526129c99085908590731441f0c929fdcb2d13d35d892ebca928a45b9d799063a8d669b49061297990600d9086908a90600090889060040161527a565b60206040518083038186803b15801561299157600080fd5b505af41580156129a5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a99919061498d565b50505050565b6000610a3c8183613fd7565b60025490565b60065490565b600083600101548311156129fd57506000612a6f565b6000838152600a8501602052604090205460ff1615612a1e57506005612a6f565b6000838152600c8501602052604090205460ff1615612a3f57506004612a6f565b6000838152600385016020526040902054612a5c57506003612a6f565b428210612a6b57506001612a6f565b5060025b9392505050565b60006123a983836040518060400160405280600481526020016329a6989960e11b815250613fe0565b808201828110156123ac576040805162461bcd60e51b81526020600480830191909152602482015263534d344560e01b604482015290519081900360640190fd5b600042612af560408501356301e13380612a9f565b109050600183602001351415612bda57600081612b2357612b1e6101a08501610180860161460a565b612b30565b6010546001600160a01b03165b9050612b7b81612b486101608701610140880161460a565b610100870135612b6061018089016101608a0161460a565b610120890135612b7660808b0160608c01614897565b614078565b612b975760405162461bcd60e51b815260040161075e90614ea4565b8215612bd457612bb881612bb360c087013560a088013561389c565b614202565b612bd45760405162461bcd60e51b815260040161075e90614f58565b50612d67565b600283602001351415612cb2576000612c10612bfe6101608601610140870161460a565b610ad36101808701610160880161460a565b509050600082612c3157612c2c6101a08601610180870161460a565b612c3e565b6010546001600160a01b03165b9050612c57828260e088013563064e6cbb60e51b614283565b612c735760405162461bcd60e51b815260040161075e90614ea4565b8315612cab57612c8f81612bb360c088013560a089013561389c565b612cab5760405162461bcd60e51b815260040161075e90614f58565b5050612d67565b600583602001351480612cc9575060068360200135145b15612d2c57600081612cec57612ce76101a08501610180860161460a565b612cf9565b6010546001600160a01b03165b9050612b7b612d106101608601610140870161460a565b82610100870135612d276080890160608a01614897565b6143a0565b600383602001351480612d43575060048360200135145b15612d6157600081612cec57612ce76101a08501610180860161460a565b50612d73565b612397600084356143ec565b5050565b600060025b6001600160a01b0383166000908152600b85016020526040902054600160ff9283161b16161515905092915050565b60048084015460405163e6a4390560e01b815260009283926001600160a01b03169163e6a4390591612de1918891889101614c5b565b60206040518083038186803b158015612df957600080fd5b505afa158015612e0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e319190614626565b91506001600160a01b038216612e595760405162461bcd60e51b815260040161075e90614f76565b826001600160a01b0316846001600160a01b0316119050935093915050565b6000808080731441f0c929fdcb2d13d35d892ebca928a45b9d7963a8d669b4600d612eab6101608a016101408b0161460a565b6101008a01356102208b0135612ec96101a08d016101808e0161460a565b6040518663ffffffff1660e01b8152600401612ee995949392919061527a565b60206040518083038186803b158015612f0157600080fd5b505af4158015612f15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f39919061498d565b90506000731441f0c929fdcb2d13d35d892ebca928a45b9d7963a8d669b4600d612f6b6101808b016101608c0161460a565b6101208b01356102408c0135612f896101a08e016101808f0161460a565b6040518663ffffffff1660e01b8152600401612fa995949392919061527a565b60206040518083038186803b158015612fc157600080fd5b505af4158015612fd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ff9919061498d565b9050856001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561303657600080fd5b505af115801561304a573d6000803e3d6000fd5b50505050730ec2323adafbebc6c80257c7359692bcceb0b3f1637a528bd2878961018001602081019061307d919061460a565b61308f6101608c016101408d0161460a565b6130a16101808d016101608e0161460a565b87876040518763ffffffff1660e01b81526004016130c496959493929190614cb0565b60606040518083038186803b1580156130dc57600080fd5b505af41580156130f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061311491906149e9565b9199909850909650945050505050565b60606000846001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561316157600080fd5b505afa158015613175573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131999190614626565b6001600160a01b0316636a9150fe85856040518363ffffffff1660e01b81526004016131c692919061526c565b60206040518083038186803b1580156131de57600080fd5b505afa1580156131f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613216919061498d565b90508060405160200161322991906152c4565b6040516020818303038152906040529150509392505050565b811561325357613253848684613921565b8015610a2957610a29838683613921565b60006003612d7c565b600080600080856001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401604080518083038186803b1580156132ab57600080fd5b505afa1580156132bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132e39190614943565b915091506132f760018861178d578261178f565b925050506000846001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561333657600080fd5b505afa15801561334a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061336e9190614626565b90506000856001600160a01b03166354cf2aeb6040518163ffffffff1660e01b815260040160206040518083038186803b1580156133ab57600080fd5b505afa1580156133bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e3919061498d565b90506000731441f0c929fdcb2d13d35d892ebca928a45b9d7963a8d669b4600d6134156101608d016101408e0161460a565b8c61010001358d61022001358e610180016020810190613435919061460a565b6040518663ffffffff1660e01b815260040161345595949392919061527a565b60206040518083038186803b15801561346d57600080fd5b505af4158015613481573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134a5919061498d565b905087613531576040516304a8fad760e31b81526001600160a01b03841690632547d6b8906134dc90859085908b90600401615313565b60206040518083038186803b1580156134f457600080fd5b505afa158015613508573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061352c919061498d565b6135b1565b60405163c4109d2560e01b81526001600160a01b0384169063c4109d259061356190859085908b90600401615313565b60206040518083038186803b15801561357957600080fd5b505afa15801561358d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b1919061498d565b9450600084861115613701576135d6866135d06101208d01358861389c565b90614400565b60405163a7d2087760e01b815290915082906001600160a01b0386169063a7d208779061360d908d9088908b908e90600401614de0565b604080518083038186803b15801561362457600080fd5b505afa158015613638573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061365c91906149c6565b600f549098509093506001600160a01b03166136806101608d016101408e0161460a565b6001600160a01b03161480156136a157506136a160808c0160608d01614897565b156136ca576136c56136bb6101a08d016101808e0161460a565b611a5e8386612a76565b6136fb565b6136fb6136df6101608d016101408e0161460a565b6136f16101a08e016101808f0161460a565b611a998487612a76565b50613709565b506101208901355b6001600160a01b03881660009081526013602052604090205461373190879061ffff16612a76565b9550808610156137535760405162461bcd60e51b815260040161075e90614efe565b61376f6137686101608c016101408d0161460a565b8984613921565b5050505050949350505050565b600f54604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906137ac9084906004016152c4565b600060405180830381600087803b1580156137c657600080fd5b505af11580156137da573d6000803e3d6000fd5b50506000808052600960205260008051602061539c833981519152546040519193506001600160a01b038616925090849061381490614c44565b600060405180830381858888f193505050503d8060008114613852576040519150601f19603f3d011682016040523d82523d6000602084013e613857565b606091505b50509050806123975760405163032b310f60e51b8152731441f0c929fdcb2d13d35d892ebca928a45b9d799063656621e09061152e90600d908790879060040161507f565b60008115806138b7575050808202828282816138b457fe5b04145b6123ac576040805162461bcd60e51b81526020600480830191909152602482015263534d324160e01b604482015290519081900360640190fd5b60006138fd8383614400565b9050613909828261389c565b83146123ac5761391a816001612a9f565b90506123ac565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b6020831061399d5780518252601f19909201916020918201910161397e565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146139ff576040519150601f19603f3d011682016040523d82523d6000602084013e613a04565b606091505b5091509150818015613a32575080511580613a325750808060200190516020811015613a2f57600080fd5b50515b610a29576040805162461bcd60e51b815260206004808301919091526024820152635448303560e01b604482015290519081900360640190fd5b60006001612d7c565b600282018054600101908190558114612d735760405162461bcd60e51b815260040161075e90614fee565b60005a9050613ab160008335613a75565b60008030613b35613b2a600984613ad06101808a016101608b0161460a565b6001600160a01b0316815260208101919091526040016000908120549061083b90600990613b066101608c016101408d0161460a565b6001600160a01b03168152602081019190915260400160002054620108dc90612a9f565b60a087013590612a76565b60405163303a892b60e01b90613b4f9088906024016152a6565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613b8d9190614c28565b60006040518083038160008787f1925050503d8060008114613bcb576040519150601f19603f3d011682016040523d82523d6000602084013e613bd0565b606091505b509092509050600182613c3557613c32613bf26101a08701610180880161460a565b613c046101608801610140890161460a565b610100880135613c1c6101808a016101608b0161460a565b6101208a0135612b7660808c0160608d01614897565b90505b613c3e81614450565b600080613c6660a088013560c089013588613c616101a08c016101808d0161460a565b614471565b915091508415156000600201547ff0cc99aeb224e65869630a14e23683d20b9c535c00427b50024ce8b6b21d35c3868585604051613ca693929190614e11565b60405180910390a350505050505050565b60005a9050613cc860008335613a75565b60008030613cde613b2a620108dc61d6d8612a9f565b60405163714abbf760e11b90613cf89088906024016152a6565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613d369190614c28565b60006040518083038160008787f1925050503d8060008114613d74576040519150601f19603f3d011682016040523d82523d6000602084013e613d79565b606091505b509092509050600182613c35576000613daf613d9d6101608801610140890161460a565b610ad361018089016101608a0161460a565b509050613dda81613dc86101a089016101808a0161460a565b60e089013563064e6cbb60e51b614283565b915050613c3e81614450565b60005a9050613df760008335613a75565b60008030613e16613b2a600984613b066101608a016101408b0161460a565b604051631a3d8e8d60e21b90613e309088906024016152a6565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613e6e9190614c28565b60006040518083038160008787f1925050503d8060008114613eac576040519150601f19603f3d011682016040523d82523d6000602084013e613eb1565b606091505b509092509050600182613c3557613c32613ed36101608701610140880161460a565b613ee56101a08801610180890161460a565b610100880135612d2760808a0160608b01614897565b60005a9050613f0c60008335613a75565b60008030613f2b613b2a600984613b066101608a016101408b0161460a565b6040516389e707ad60e01b90613e309088906024016152a6565b6040516000906001600160a01b038516908390859084818181858888f193505050503d8060008114613f93576040519150601f19603f3d011682016040523d82523d6000602084013e613f98565b606091505b50509050806129c9576040805162461bcd60e51b815260206004808301919091526024820152632a2419a360e11b604482015290519081900360640190fd5b60006004612d7c565b81830381848211156140705760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561403557818101518382015260200161401d565b50505050905090810190601f1680156140625780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509392505050565b6001600160a01b0383811660009081526009602052604080822054928816825281205490918291829130916140ac91612a9f565b604051633ed76f1760e01b906140d0908d908d908d908d908d908d90602401614cea565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161410e9190614c28565b60006040518083038160008787f1925050503d806000811461414c576040519150601f19603f3d011682016040523d82523d6000602084013e614151565b606091505b5091509150816141f657876001600160a01b0316896001600160a01b03167f786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b21159289846040516141a09291906152cd565b60405180910390a3856001600160a01b0316896001600160a01b03167f786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b21159287846040516141ed9291906152cd565b60405180910390a35b50979650505050505050565b600081614211575060016123ac565b60008052600960205260008051602061539c833981519152546142379084908490614501565b9050801515836001600160a01b03167fdbef2fc26e7694e7a1c5a4801b1ad144136d149cf76f310a780689b4087f0ffe8460405161427591906152c4565b60405180910390a392915050565b60008261429257506001614398565b600080306001600160a01b031661d6d88589898960006040516024016142bb9493929190614d24565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516142f99190614c28565b60006040518083038160008787f1925050503d8060008114614337576040519150601f19603f3d011682016040523d82523d6000602084013e61433c565b606091505b50915091508161439457866001600160a01b0316866001600160a01b03167f786212e89f390a4c768f3b935b85e0ec2561a24b6f48cda3c4b48a996b211592878460405161438b9291906152cd565b60405180910390a35b5090505b949350505050565b6000826143af57506001614398565b6001600160a01b0385166000908152600960205260408082205490518291309163e5b1be6560e01b906142bb908b908b908b908b90602401614d24565b600090815260039091016020526040812055565b600080821161443f576040805162461bcd60e51b81526020600480830191909152602482015263534d343360e01b604482015290519081900360640190fd5b81838161444857fe5b049392505050565b806144645761445f600061455f565b61446e565b61446e6000614582565b50565b6000808061447f878761389c565b90506144926193ac61083b5a8890612a76565b925060006144b7826144b26000600601548761389c90919063ffffffff16565b61459b565b90506144c38282612a76565b92506144cf3382614202565b6144eb5760405162461bcd60e51b815260040161075e90614f58565b6144f58584614202565b50505094509492505050565b6040516000906001600160a01b038516908390859084818181858888f193505050503d806000811461454f576040519150601f19603f3d011682016040523d82523d6000602084013e614554565b606091505b509095945050505050565b60028101546000908152600c90910160205260409020805460ff19166001179055565b6002810154600090815260039091016020526040812055565b60008183106145aa57816123a9565b5090919050565b8035610a3f81615378565b8035610a3f8161538d565b600061010082840312156145d9578081fd5b50919050565b80516001600160701b0381168114610a3f57600080fd5b803563ffffffff81168114610a3f57600080fd5b60006020828403121561461b578081fd5b8135612a6f81615378565b600060208284031215614637578081fd5b8151612a6f81615378565b600080600060608486031215614656578182fd5b833561466181615378565b9250602084013561467181615378565b929592945050506040919091013590565b60008060008060008060c0878903121561469a578182fd5b86356146a581615378565b955060208701356146b581615378565b94506040870135935060608701356146cc81615378565b92506080870135915060a08701356146e38161538d565b809150509295509295509295565b60008060008060808587031215614706578384fd5b843561471181615378565b9350602085013561472181615378565b92506040850135915060608501356147388161538d565b939692955090935050565b60008060408385031215614755578182fd5b823561476081615378565b915060208301356147708161538d565b809150509250929050565b60008060006060848603121561478f578283fd5b833561479a81615378565b92506020840135600581106147ad578283fd5b915060408401356147bd8161538d565b809150509250925092565b600080604083850312156147da578182fd5b82356147e581615378565b9150602083013561ffff81168114614770578182fd5b6000806040838503121561480d578081fd5b823561481881615378565b946020939093013593505050565b60008060208385031215614838578182fd5b823567ffffffffffffffff8082111561484f578384fd5b818501915085601f830112614862578384fd5b813581811115614870578485fd5b86602061026083028501011115614885578485fd5b60209290920196919550909350505050565b6000602082840312156148a8578081fd5b8135612a6f8161538d565b600080600080608085870312156148c8578182fd5b84516148d38161538d565b60208601516040870151606090970151919890975090945092505050565b60006101008284031215614903578081fd5b6123a983836145c7565b600061016082840312156145d9578081fd5b600061026082840312156145d9578081fd5b600061012082840312156145d9578081fd5b60008060408385031215614955578182fd5b61495e836145df565b915061496c602084016145df565b90509250929050565b600060208284031215614986578081fd5b5035919050565b60006020828403121561499e578081fd5b5051919050565b600080604083850312156149b7578182fd5b50508035926020909101359150565b600080604083850312156149d8578182fd5b505080516020909101519092909150565b6000806000606084860312156149fd578081fd5b8351925060208401519150604084015190509250925092565b600060208284031215614a27578081fd5b6123a9826145f6565b6001600160a01b03169052565b15159052565b60008151808452614a5b81602086016020860161534c565b601f01601f19169290920160200192915050565b8035614a7a81615378565b6001600160a01b039081168352602082013590614a9682615378565b16602083015260408181013590830152606080820135908301526080810135614abe8161538d565b1515608083015260a0810135614ad381615378565b614ae060a0840182614a30565b5060c081013560c0830152614af760e082016145f6565b61239760e0840182614c1e565b803582526020810135602083015260408101356040830152614b28606082016145bc565b614b356060840182614a3d565b506080810135608083015260a081013560a083015260c081013560c083015260e081013560e0830152610100808201358184015250610120808201358184015250610140614b848183016145b1565b614b9082850182614a30565b5050610160614ba08183016145b1565b614bac82850182614a30565b5050610180614bbc8183016145b1565b614bc882850182614a30565b50506101a081810135908301526101c080820135908301526101e0614bee8183016145bc565b614bfa82850182614a3d565b50506102008181013590830152610220808201359083015261024090810135910152565b63ffffffff169052565b60008251614c3a81846020870161534c565b9190910192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039687168152948616602086015292851660408501529084166060840152909216608082015260a081019190915260c00190565b6001600160a01b0396871681529486166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b6001600160a01b0396871681529486166020860152604085019390935293166060830152608082019290925290151560a082015260c00190565b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b6001600160a01b03878116825286166020820152604081018590526060810184905261ffff8316608082015260c060a08201819052600090614d9190830184614a43565b98975050505050505050565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b0392909216825261ffff16602082015260400190565b901515815260200190565b6000851515825284602083015283604083015260806060830152614e076080830184614a43565b9695505050505050565b600060608252614e246060830186614a43565b60208301949094525060400152919050565b6020810160068310614e4457fe5b91905290565b60208082526004908201526315110dcd60e21b604082015260600190565b6020808252600490820152632a22181b60e11b604082015260600190565b6020808252600490820152635444314360e01b604082015260600190565b60208082526004908201526315110c4d60e21b604082015260600190565b6020808252600490820152635444323160e01b604082015260600190565b6020808252600490820152635444303360e01b604082015260600190565b6020808252600490820152635444333760e01b604082015260600190565b6020808252600490820152630544430360e41b604082015260600190565b6020808252600490820152635444303160e01b604082015260600190565b6020808252600490820152630544434360e41b604082015260600190565b6020808252600490820152634f53313760e01b604082015260600190565b60208082526004908201526315110d4d60e21b604082015260600190565b60208082526004908201526315110c0d60e21b604082015260600190565b6020808252600490820152632a221a9960e11b604082015260600190565b60208082526004908201526327a99b9960e11b604082015260600190565b6020808252600490820152632a22181960e11b604082015260600190565b6020808252600490820152630a88860760e31b604082015260600190565b8481526001600160a01b0384166020820152608081016005841061506857fe5b836040830152821515606083015295945050505050565b9283526001600160a01b03919091166020830152604082015260600190565b83815261014081016150b36020830185614a6f565b82610120830152949350505050565b8381526101a081016150df602083016150da866145b1565b614a30565b6150eb602085016145b1565b6150f86040840182614a30565b506040840135606083015260608401356080830152608084013560a083015260a084013560c083015261512d60c085016145bc565b61513a60e0840182614a3d565b5061514760e085016145bc565b61010061515681850183614a3d565b6151618187016145b1565b91505061012061517381850183614a30565b610140915080860135828501525061518c8186016145f6565b905061519c610160840182614c1e565b5082610180830152949350505050565b8281526102808101612a6f6020830184614b04565b82815261014081016151d9602083016150da856145b1565b6151e5602084016145b1565b6151f26040840182614a30565b506040830135606083015260608301356080830152608083013560a083015261521d60a084016145bc565b61522a60c0840182614a3d565b5061523760c084016145b1565b61524460e0840182614a30565b5061010060e08401358184015261525c8185016145f6565b9050614070610120840182614c1e565b918252602082015260400190565b9485526001600160a01b0393841660208601526040850192909252606084015216608082015260a00190565b61026081016123ac8284614b04565b61ffff91909116815260200190565b90815260200190565b6000838252604060208301526143986040830184614a43565b600085825284602083015260018060a01b038416604083015260806060830152614e076080830184614a43565b6000848252836020830152606060408301526153326060830184614a43565b95945050505050565b63ffffffff91909116815260200190565b60005b8381101561536757818101518382015260200161534f565b838111156129c95750506000910152565b6001600160a01b038116811461446e57600080fd5b801515811461446e57600080fdfeec8156718a8372b1db44bb411437d0870f3e3790d4a08526d024ce1b0b668f6ba26469706673582212208aa322a455c1087b5f4e71b05ad4ffd280aef00d7c7ca850d097bde81bbccf0264736f6c63430007060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c6000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000003a1d749fa4a9e650fce844ff1c58c5faf7e2a9d1
-----Decoded View---------------
Arg [0] : _factory (address): 0xC480b33eE5229DE3FbDFAD1D2DCD3F3BAD0C56c6
Arg [1] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [2] : _bot (address): 0x3a1D749fa4a9E650FCe844fF1C58C5faf7e2a9D1
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000c480b33ee5229de3fbdfad1d2dcd3f3bad0c56c6
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [2] : 0000000000000000000000003a1d749fa4a9e650fce844ff1c58c5faf7e2a9d1
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.