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