文件 1 的 18:AddLiquidity.sol
pragma solidity 0.7.6;
import './TransferHelper.sol';
import './SafeMath.sol';
import './Math.sol';
import '../interfaces/ITwapPair.sol';
import '../interfaces/ITwapOracle.sol';
library AddLiquidity {
using SafeMath for uint256;
function addLiquidity(
address pair,
uint256 amount0Desired,
uint256 amount1Desired
)
internal
view
returns (
uint256 amount0,
uint256 amount1,
uint256 swapToken
)
{
if (amount0Desired == 0 || amount1Desired == 0) {
if (amount0Desired > 0) {
swapToken = 1;
} else if (amount1Desired > 0) {
swapToken = 2;
}
return (0, 0, swapToken);
}
(uint256 reserve0, uint256 reserve1) = ITwapPair(pair).getReserves();
if (reserve0 == 0 && reserve1 == 0) {
(amount0, amount1) = (amount0Desired, amount1Desired);
} else {
require(reserve0 > 0 && reserve1 > 0, 'AL07');
uint256 amount1Optimal = amount0Desired.mul(reserve1) / reserve0;
if (amount1Optimal <= amount1Desired) {
swapToken = 2;
(amount0, amount1) = (amount0Desired, amount1Optimal);
} else {
uint256 amount0Optimal = amount1Desired.mul(reserve0) / reserve1;
assert(amount0Optimal <= amount0Desired);
swapToken = 1;
(amount0, amount1) = (amount0Optimal, amount1Desired);
}
uint256 totalSupply = ITwapPair(pair).totalSupply();
uint256 liquidityOut = Math.min(amount0.mul(totalSupply) / reserve0, amount1.mul(totalSupply) / reserve1);
if (liquidityOut == 0) {
amount0 = 0;
amount1 = 0;
}
}
}
function addLiquidityAndMint(
address pair,
address to,
address token0,
address token1,
uint256 amount0Desired,
uint256 amount1Desired
)
external
returns (
uint256 amount0Left,
uint256 amount1Left,
uint256 swapToken
)
{
uint256 amount0;
uint256 amount1;
(amount0, amount1, swapToken) = addLiquidity(pair, amount0Desired, amount1Desired);
if (amount0 == 0 || amount1 == 0) {
return (amount0Desired, amount1Desired, swapToken);
}
TransferHelper.safeTransfer(token0, pair, amount0);
TransferHelper.safeTransfer(token1, pair, amount1);
ITwapPair(pair).mint(to);
amount0Left = amount0Desired.sub(amount0);
amount1Left = amount1Desired.sub(amount1);
}
function swapDeposit0(
address pair,
address token0,
uint256 amount0,
uint256 minSwapPrice,
uint16 tolerance,
bytes calldata data
) external returns (uint256 amount0Left, uint256 amount1Left) {
uint256 amount0In = ITwapPair(pair).getDepositAmount0In(amount0, data);
amount1Left = ITwapPair(pair).getSwapAmount1Out(amount0In, data).sub(tolerance);
if (amount1Left == 0) {
return (amount0, amount1Left);
}
uint256 price = getPrice(amount0In, amount1Left, pair);
require(minSwapPrice == 0 || price >= minSwapPrice, 'AL15');
TransferHelper.safeTransfer(token0, pair, amount0In);
ITwapPair(pair).swap(0, amount1Left, address(this), data);
amount0Left = amount0.sub(amount0In);
}
function swapDeposit1(
address pair,
address token1,
uint256 amount1,
uint256 maxSwapPrice,
uint16 tolerance,
bytes calldata data
) external returns (uint256 amount0Left, uint256 amount1Left) {
uint256 amount1In = ITwapPair(pair).getDepositAmount1In(amount1, data);
amount0Left = ITwapPair(pair).getSwapAmount0Out(amount1In, data).sub(tolerance);
if (amount0Left == 0) {
return (amount0Left, amount1);
}
uint256 price = getPrice(amount0Left, amount1In, pair);
require(maxSwapPrice == 0 || price <= maxSwapPrice, 'AL16');
TransferHelper.safeTransfer(token1, pair, amount1In);
ITwapPair(pair).swap(amount0Left, 0, address(this), data);
amount1Left = amount1.sub(amount1In);
}
function getPrice(
uint256 amount0,
uint256 amount1,
address pair
) internal view returns (uint256) {
ITwapOracle oracle = ITwapOracle(ITwapPair(pair).oracle());
return amount1.mul(uint256(oracle.decimalsConverter())).div(amount0);
}
function _refundDeposit(
address to,
address token0,
address token1,
uint256 amount0,
uint256 amount1
) internal {
if (amount0 > 0) {
TransferHelper.safeTransfer(token0, to, amount0);
}
if (amount1 > 0) {
TransferHelper.safeTransfer(token1, to, amount1);
}
}
}
文件 2 的 18:ExecutionHelper.sol
pragma solidity 0.7.6;
pragma abicoder v2;
import '../interfaces/ITwapOracle.sol';
import '../interfaces/ITwapPair.sol';
import '../interfaces/IWETH.sol';
import '../libraries/SafeMath.sol';
import '../libraries/Orders.sol';
import '../libraries/TokenShares.sol';
import '../libraries/AddLiquidity.sol';
import '../libraries/WithdrawHelper.sol';
library ExecutionHelper {
using SafeMath for uint256;
using TransferHelper for address;
using Orders for Orders.Data;
using TokenShares for TokenShares.Data;
uint256 private constant ORDER_LIFESPAN = 48 hours;
struct ExecuteBuySellParams {
Orders.Order order;
address pairAddress;
uint16 pairTolerance;
}
function executeDeposit(
Orders.Order calldata order,
address pairAddress,
uint16 pairTolerance,
TokenShares.Data storage tokenShares
) external {
require(order.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'EH04');
(uint256 amount0Left, uint256 amount1Left, uint256 swapToken) = _initialDeposit(
order,
pairAddress,
tokenShares
);
if (order.swap && swapToken != 0) {
bytes memory data = encodePriceInfo(pairAddress, order.priceAccumulator, order.timestamp);
if (amount0Left != 0 && swapToken == 1) {
uint256 extraAmount1;
(amount0Left, extraAmount1) = AddLiquidity.swapDeposit0(
pairAddress,
order.token0,
amount0Left,
order.minSwapPrice,
pairTolerance,
data
);
amount1Left = amount1Left.add(extraAmount1);
} else if (amount1Left != 0 && swapToken == 2) {
uint256 extraAmount0;
(extraAmount0, amount1Left) = AddLiquidity.swapDeposit1(
pairAddress,
order.token1,
amount1Left,
order.maxSwapPrice,
pairTolerance,
data
);
amount0Left = amount0Left.add(extraAmount0);
}
}
if (amount0Left != 0 && amount1Left != 0) {
(amount0Left, amount1Left, ) = AddLiquidity.addLiquidityAndMint(
pairAddress,
order.to,
order.token0,
order.token1,
amount0Left,
amount1Left
);
}
AddLiquidity._refundDeposit(order.to, order.token0, order.token1, amount0Left, amount1Left);
}
function _initialDeposit(
Orders.Order calldata order,
address pairAddress,
TokenShares.Data storage tokenShares
)
private
returns (
uint256 amount0Left,
uint256 amount1Left,
uint256 swapToken
)
{
uint256 amount0Desired = tokenShares.sharesToAmount(order.token0, order.value0, order.amountLimit0, order.to);
uint256 amount1Desired = tokenShares.sharesToAmount(order.token1, order.value1, order.amountLimit1, order.to);
(amount0Left, amount1Left, swapToken) = AddLiquidity.addLiquidityAndMint(
pairAddress,
order.to,
order.token0,
order.token1,
amount0Desired,
amount1Desired
);
}
function executeWithdraw(Orders.Order calldata order) external {
require(order.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'EH04');
(address pairAddress, ) = Orders.getPair(order.token0, order.token1);
TransferHelper.safeTransfer(pairAddress, pairAddress, order.liquidity);
uint256 wethAmount;
uint256 amount0;
uint256 amount1;
if (order.unwrap && (order.token0 == TokenShares.WETH_ADDRESS || order.token1 == TokenShares.WETH_ADDRESS)) {
bool success;
(success, wethAmount, amount0, amount1) = WithdrawHelper.withdrawAndUnwrap(
order.token0,
order.token1,
pairAddress,
TokenShares.WETH_ADDRESS,
order.to,
Orders.getTransferGasCost(Orders.NATIVE_CURRENCY_SENTINEL)
);
if (!success) {
TokenShares.onUnwrapFailed(order.to, wethAmount);
}
} else {
(amount0, amount1) = ITwapPair(pairAddress).burn(order.to);
}
require(amount0 >= order.value0 && amount1 >= order.value1, 'EH03');
}
function executeBuy(ExecuteBuySellParams memory orderParams, TokenShares.Data storage tokenShares) external {
require(orderParams.order.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'EH04');
uint256 amountInMax = tokenShares.sharesToAmount(
orderParams.order.token0,
orderParams.order.value0,
orderParams.order.amountLimit0,
orderParams.order.to
);
bytes memory priceInfo = encodePriceInfo(
orderParams.pairAddress,
orderParams.order.priceAccumulator,
orderParams.order.timestamp
);
uint256 amountIn;
uint256 amountOut;
uint256 reserveOut;
bool inverted = orderParams.order.inverted;
{
(uint112 reserve0, uint112 reserve1) = ITwapPair(orderParams.pairAddress).getReserves();
reserveOut = uint256(inverted ? reserve0 : reserve1).sub(1);
}
{
address oracle = ITwapPair(orderParams.pairAddress).oracle();
uint256 swapFee = ITwapPair(orderParams.pairAddress).swapFee();
(amountIn, amountOut) = ITwapOracle(oracle).getSwapAmountInMaxOut(
inverted,
swapFee,
orderParams.order.value1,
priceInfo
);
uint256 amountInMaxScaled;
if (amountOut > reserveOut) {
amountInMaxScaled = amountInMax.mul(reserveOut).ceil_div(orderParams.order.value1);
(amountIn, amountOut) = ITwapOracle(oracle).getSwapAmountInMinOut(
inverted,
swapFee,
reserveOut,
priceInfo
);
} else {
amountInMaxScaled = amountInMax;
amountOut = orderParams.order.value1;
}
require(amountInMaxScaled >= amountIn, 'EH08');
if (amountInMax > amountIn) {
if (orderParams.order.token0 == TokenShares.WETH_ADDRESS && orderParams.order.unwrap) {
forceEtherTransfer(orderParams.order.to, amountInMax.sub(amountIn));
} else {
TransferHelper.safeTransfer(
orderParams.order.token0,
orderParams.order.to,
amountInMax.sub(amountIn)
);
}
}
TransferHelper.safeTransfer(orderParams.order.token0, orderParams.pairAddress, amountIn);
}
amountOut = amountOut.sub(orderParams.pairTolerance);
uint256 amount0Out;
uint256 amount1Out;
if (inverted) {
amount0Out = amountOut;
} else {
amount1Out = amountOut;
}
if (orderParams.order.token1 == TokenShares.WETH_ADDRESS && orderParams.order.unwrap) {
ITwapPair(orderParams.pairAddress).swap(amount0Out, amount1Out, address(this), priceInfo);
forceEtherTransfer(orderParams.order.to, amountOut);
} else {
ITwapPair(orderParams.pairAddress).swap(amount0Out, amount1Out, orderParams.order.to, priceInfo);
}
}
function executeSell(ExecuteBuySellParams memory orderParams, TokenShares.Data storage tokenShares) external {
require(orderParams.order.validAfterTimestamp + ORDER_LIFESPAN >= block.timestamp, 'EH04');
bytes memory priceInfo = encodePriceInfo(
orderParams.pairAddress,
orderParams.order.priceAccumulator,
orderParams.order.timestamp
);
uint256 amountOut = _executeSellHelper(orderParams, priceInfo, tokenShares);
(uint256 amount0Out, uint256 amount1Out) = orderParams.order.inverted
? (amountOut, uint256(0))
: (uint256(0), amountOut);
if (orderParams.order.token1 == TokenShares.WETH_ADDRESS && orderParams.order.unwrap) {
ITwapPair(orderParams.pairAddress).swap(amount0Out, amount1Out, address(this), priceInfo);
forceEtherTransfer(orderParams.order.to, amountOut);
} else {
ITwapPair(orderParams.pairAddress).swap(amount0Out, amount1Out, orderParams.order.to, priceInfo);
}
}
function _executeSellHelper(
ExecuteBuySellParams memory orderParams,
bytes memory priceInfo,
TokenShares.Data storage tokenShares
) internal returns (uint256 amountOut) {
uint256 reserveOut;
{
(uint112 reserve0, uint112 reserve1) = ITwapPair(orderParams.pairAddress).getReserves();
reserveOut = uint256(orderParams.order.inverted ? reserve0 : reserve1).sub(1);
}
{
address oracle = ITwapPair(orderParams.pairAddress).oracle();
uint256 swapFee = ITwapPair(orderParams.pairAddress).swapFee();
uint256 amountIn = tokenShares.sharesToAmount(
orderParams.order.token0,
orderParams.order.value0,
orderParams.order.amountLimit0,
orderParams.order.to
);
amountOut = orderParams.order.inverted
? ITwapOracle(oracle).getSwapAmount0Out(swapFee, amountIn, priceInfo)
: ITwapOracle(oracle).getSwapAmount1Out(swapFee, amountIn, priceInfo);
uint256 amountOutMinScaled;
if (amountOut > reserveOut) {
amountOutMinScaled = orderParams.order.value1.mul(reserveOut).div(amountOut);
uint256 _amountIn = amountIn;
(amountIn, amountOut) = ITwapOracle(oracle).getSwapAmountInMinOut(
orderParams.order.inverted,
swapFee,
reserveOut,
priceInfo
);
if (orderParams.order.token0 == TokenShares.WETH_ADDRESS && orderParams.order.unwrap) {
forceEtherTransfer(orderParams.order.to, _amountIn.sub(amountIn));
} else {
TransferHelper.safeTransfer(
orderParams.order.token0,
orderParams.order.to,
_amountIn.sub(amountIn)
);
}
} else {
amountOutMinScaled = orderParams.order.value1;
}
amountOut = amountOut.sub(orderParams.pairTolerance);
require(amountOut >= amountOutMinScaled, 'EH37');
TransferHelper.safeTransfer(orderParams.order.token0, orderParams.pairAddress, amountIn);
}
}
function encodePriceInfo(
address pairAddress,
uint256 priceAccumulator,
uint256 priceTimestamp
) internal view returns (bytes memory data) {
uint256 price = ITwapOracle(ITwapPair(pairAddress).oracle()).getAveragePrice(priceAccumulator, priceTimestamp);
data = abi.encode(price);
}
function forceEtherTransfer(address to, uint256 amount) internal {
IWETH(TokenShares.WETH_ADDRESS).withdraw(amount);
(bool success, ) = to.call{ value: amount, gas: Orders.getTransferGasCost(Orders.NATIVE_CURRENCY_SENTINEL) }(
''
);
if (!success) {
TokenShares.onUnwrapFailed(to, amount);
}
}
}
文件 3 的 18:IERC20.sol
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);
}
文件 4 的 18:IReserves.sol
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);
}
文件 5 的 18:ITwapDelay.sol
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 EthRefund(address indexed to, bool indexed success, uint256 value);
event OwnerSet(address owner);
event FactoryGovernorSet(address factoryGovernor);
event BotSet(address bot, bool isBot);
event DelaySet(uint256 delay);
event RelayerSet(address relayer);
event MaxGasLimitSet(uint256 maxGasLimit);
event GasPriceInertiaSet(uint256 gasPriceInertia);
event MaxGasPriceImpactSet(uint256 maxGasPriceImpact);
event TransferGasCostSet(address token, uint256 gasCost);
event ToleranceSet(address pair, uint16 amount);
event NonRebasingTokenSet(address token, bool isNonRebasing);
function factory() external view returns (address);
function factoryGovernor() external view returns (address);
function relayer() external view returns (address);
function owner() external view returns (address);
function isBot(address bot) external view returns (bool);
function getTolerance(address pair) external view returns (uint16);
function isNonRebasingToken(address token) external view returns (bool);
function gasPriceInertia() external view returns (uint256);
function gasPrice() external view returns (uint256);
function maxGasPriceImpact() external view returns (uint256);
function maxGasLimit() external view returns (uint256);
function delay() external view returns (uint256);
function totalShares(address token) external view returns (uint256);
function weth() external view returns (address);
function getTransferGasCost(address token) external pure returns (uint256);
function getDepositDisabled(address pair) external view returns (bool);
function getWithdrawDisabled(address pair) external view returns (bool);
function getBuyDisabled(address pair) external view returns (bool);
function getSellDisabled(address pair) external view returns (bool);
function getOrderStatus(uint256 orderId, uint256 validAfterTimestamp) external view returns (Orders.OrderStatus);
function setOrderTypesDisabled(
address pair,
Orders.OrderType[] calldata orderTypes,
bool disabled
) external;
function setOwner(address _owner) external;
function setFactoryGovernor(address _factoryGovernor) external;
function setBot(address _bot, bool _isBot) external;
function deposit(Orders.DepositParams memory depositParams) external payable returns (uint256 orderId);
function withdraw(Orders.WithdrawParams memory withdrawParams) external payable returns (uint256 orderId);
function sell(Orders.SellParams memory sellParams) external payable returns (uint256 orderId);
function relayerSell(Orders.SellParams memory sellParams) external payable returns (uint256 orderId);
function buy(Orders.BuyParams memory buyParams) external payable returns (uint256 orderId);
function execute(Orders.Order[] calldata orders) external payable;
function retryRefund(Orders.Order calldata order) external;
function cancelOrder(Orders.Order calldata order) external;
function syncPair(address token0, address token1) external returns (address pairAddress);
}
文件 6 的 18:ITwapERC20.sol
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);
}
文件 7 的 18:ITwapFactory.sol
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;
}
文件 8 的 18:ITwapFactoryGovernor.sol
pragma solidity 0.7.6;
interface ITwapFactoryGovernor {
event FactorySet(address factory);
event DelaySet(address delay);
event ProtocolFeeRatioSet(uint256 protocolFeeRatio);
event EthTransferCostSet(uint256 ethTransferCost);
event FeeDistributed(address indexed token, address indexed pair, uint256 lpAmount, uint256 protocolAmount);
event OwnerSet(address owner);
event WithdrawToken(address token, address to, uint256 amount);
function owner() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint256) external view returns (address pair);
function allPairsLength() external view returns (uint256);
function factory() external view returns (address);
function delay() external view returns (address);
function protocolFeeRatio() external view returns (uint256);
function ethTransferCost() external view returns (uint256);
function setFactoryOwner(address) external;
function setFactory(address) external;
function setOwner(address) external;
function setMintFee(
address tokenA,
address tokenB,
uint256 fee
) external;
function setBurnFee(
address tokenA,
address tokenB,
uint256 fee
) external;
function setSwapFee(
address tokenA,
address tokenB,
uint256 fee
) external;
function setOracle(
address tokenA,
address tokenB,
address oracle
) external;
function setTrader(
address tokenA,
address tokenB,
address trader
) external;
function setDelay(address) external;
function setProtocolFeeRatio(uint256 _protocolFeeRatio) external;
function setEthTransferCost(uint256 _ethTransferCost) external;
function createPair(
address tokenA,
address tokenB,
address oracle,
address trader
) external returns (address pair);
function collectFees(
address tokenA,
address tokenB,
address to
) external;
function withdrawLiquidity(
address tokenA,
address tokenB,
uint256 amount,
address to
) external;
function withdrawToken(
address token,
uint256 amount,
address to
) external;
function distributeFees(address tokenA, address tokenB) external;
function distributeFees(
address tokenA,
address tokenB,
address pairAddress
) external;
function feesToDistribute(address tokenA, address tokenB)
external
view
returns (uint256 fee0ToDistribute, uint256 fee1ToDistribute);
}
文件 9 的 18:ITwapOracle.sol
pragma solidity 0.7.6;
interface ITwapOracle {
event OwnerSet(address owner);
event UniswapPairSet(address uniswapPair);
function decimalsConverter() external view returns (int256);
function xDecimals() external view returns (uint8);
function yDecimals() external view returns (uint8);
function owner() external view returns (address);
function uniswapPair() external view returns (address);
function getPriceInfo() external view returns (uint256 priceAccumulator, uint256 priceTimestamp);
function getSpotPrice() external view returns (uint256);
function getAveragePrice(uint256 priceAccumulator, uint256 priceTimestamp) external view returns (uint256);
function setOwner(address _owner) external;
function setUniswapPair(address _uniswapPair) external;
function tradeX(
uint256 xAfter,
uint256 xBefore,
uint256 yBefore,
bytes calldata data
) external view returns (uint256 yAfter);
function tradeY(
uint256 yAfter,
uint256 yBefore,
uint256 xBefore,
bytes calldata data
) external view returns (uint256 xAfter);
function depositTradeXIn(
uint256 xLeft,
uint256 xBefore,
uint256 yBefore,
bytes calldata data
) external view returns (uint256 xIn);
function depositTradeYIn(
uint256 yLeft,
uint256 yBefore,
uint256 xBefore,
bytes calldata data
) external view returns (uint256 yIn);
function getSwapAmount0Out(
uint256 swapFee,
uint256 amount1In,
bytes calldata data
) external view returns (uint256 amount0Out);
function getSwapAmount1Out(
uint256 swapFee,
uint256 amount0In,
bytes calldata data
) external view returns (uint256 amount1Out);
function getSwapAmountInMaxOut(
bool inverse,
uint256 swapFee,
uint256 _amountOut,
bytes calldata data
) external view returns (uint256 amountIn, uint256 amountOut);
function getSwapAmountInMinOut(
bool inverse,
uint256 swapFee,
uint256 _amountOut,
bytes calldata data
) external view returns (uint256 amountIn, uint256 amountOut);
}
文件 10 的 18:ITwapPair.sol
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);
}
文件 11 的 18:IWETH.sol
pragma solidity 0.7.6;
interface IWETH {
function deposit() external payable;
function transfer(address to, uint256 value) external returns (bool);
function withdraw(uint256) external;
}
文件 12 的 18:Math.sol
pragma solidity 0.7.6;
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;
}
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;
}
}
}
文件 13 的 18:Orders.sol
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 DepositEnqueued(uint256 indexed orderId, Order order);
event WithdrawEnqueued(uint256 indexed orderId, Order order);
event SellEnqueued(uint256 indexed orderId, Order order);
event BuyEnqueued(uint256 indexed orderId, Order order);
event OrderTypesDisabled(address pair, Orders.OrderType[] orderTypes, bool disabled);
event RefundFailed(address indexed to, address indexed token, uint256 amount, bytes data);
uint256 public constant ETHER_TRANSFER_COST = ETHER_TRANSFER_CALL_COST + 2600 + 1504;
uint256 private constant BOT_ETHER_TRANSFER_COST = 10_000;
uint256 private constant BUFFER_COST = 10_000;
uint256 private constant ORDER_EXECUTED_EVENT_COST = 3700;
uint256 private constant EXECUTE_PREPARATION_COST = 30_000;
uint256 public constant ETHER_TRANSFER_CALL_COST = 10_000;
uint256 public constant PAIR_TRANSFER_COST = 55_000;
uint256 public constant REFUND_BASE_COST =
BOT_ETHER_TRANSFER_COST + ETHER_TRANSFER_COST + BUFFER_COST + ORDER_EXECUTED_EVENT_COST;
uint256 public constant ORDER_BASE_COST = EXECUTE_PREPARATION_COST + REFUND_BASE_COST;
uint8 private constant DEPOSIT_MASK = uint8(1 << uint8(OrderType.Deposit));
uint8 private constant WITHDRAW_MASK = uint8(1 << uint8(OrderType.Withdraw));
uint8 private constant SELL_MASK = uint8(1 << uint8(OrderType.Sell));
uint8 private constant BUY_MASK = uint8(1 << uint8(OrderType.Buy));
address public constant FACTORY_ADDRESS = 0xC480b33eE5229DE3FbDFAD1D2DCD3F3BAD0C56c6;
uint256 public constant MAX_GAS_LIMIT = 5000000;
uint256 public constant GAS_PRICE_INERTIA = 20000000;
uint256 public constant MAX_GAS_PRICE_IMPACT = 1000000;
uint256 public constant DELAY = 1800;
address public constant NATIVE_CURRENCY_SENTINEL = address(0);
struct Data {
uint256 newestOrderId;
uint256 lastProcessedOrderId;
mapping(uint256 => bytes32) orderQueue;
uint256 gasPrice;
mapping(uint256 => bool) canceled;
mapping(address => uint8) orderTypesDisabled;
mapping(uint256 => bool) refundFailed;
}
struct Order {
uint256 orderId;
OrderType orderType;
bool inverted;
uint256 validAfterTimestamp;
bool unwrap;
uint256 timestamp;
uint256 gasLimit;
uint256 gasPrice;
uint256 liquidity;
uint256 value0;
uint256 value1;
address token0;
address token1;
address to;
uint256 minSwapPrice;
uint256 maxSwapPrice;
bool swap;
uint256 priceAccumulator;
uint256 amountLimit0;
uint256 amountLimit1;
}
function getOrderStatus(
Data storage data,
uint256 orderId,
uint256 validAfterTimestamp
) internal view returns (OrderStatus) {
if (orderId > data.newestOrderId) {
return OrderStatus.NonExistent;
}
if (data.canceled[orderId]) {
return OrderStatus.Canceled;
}
if (data.refundFailed[orderId]) {
return OrderStatus.ExecutedFailed;
}
if (data.orderQueue[orderId] == bytes32(0)) {
return OrderStatus.ExecutedSucceeded;
}
if (validAfterTimestamp >= block.timestamp) {
return OrderStatus.EnqueuedWaiting;
}
return OrderStatus.EnqueuedReady;
}
function getPair(address tokenA, address tokenB) internal view returns (address pair, bool inverted) {
pair = ITwapFactory(FACTORY_ADDRESS).getPair(tokenA, tokenB);
require(pair != address(0), 'OS17');
inverted = tokenA > tokenB;
}
function getDepositDisabled(Data storage data, address pair) internal view returns (bool) {
return data.orderTypesDisabled[pair] & DEPOSIT_MASK != 0;
}
function getWithdrawDisabled(Data storage data, address pair) internal view returns (bool) {
return data.orderTypesDisabled[pair] & WITHDRAW_MASK != 0;
}
function getSellDisabled(Data storage data, address pair) internal view returns (bool) {
return data.orderTypesDisabled[pair] & SELL_MASK != 0;
}
function getBuyDisabled(Data storage data, address pair) internal view returns (bool) {
return data.orderTypesDisabled[pair] & BUY_MASK != 0;
}
function setOrderTypesDisabled(
Data storage data,
address pair,
Orders.OrderType[] calldata orderTypes,
bool disabled
) external {
uint256 orderTypesLength = orderTypes.length;
uint8 currentSettings = data.orderTypesDisabled[pair];
uint8 combinedMask;
for (uint256 i; i < orderTypesLength; ++i) {
Orders.OrderType orderType = orderTypes[i];
require(orderType != Orders.OrderType.Empty, 'OS32');
combinedMask = combinedMask | uint8(1 << uint8(orderType));
}
if (disabled) {
currentSettings = currentSettings | combinedMask;
} else {
currentSettings = currentSettings & (combinedMask ^ 0xff);
}
require(currentSettings != data.orderTypesDisabled[pair], 'OS01');
data.orderTypesDisabled[pair] = currentSettings;
emit OrderTypesDisabled(pair, orderTypes, disabled);
}
function markRefundFailed(Data storage data) internal {
data.refundFailed[data.lastProcessedOrderId] = true;
}
function enqueueOrder(Data storage data, Order memory order) internal {
order.orderId = ++data.newestOrderId;
data.orderQueue[order.orderId] = getOrderDigest(order);
}
struct DepositParams {
address token0;
address token1;
uint256 amount0;
uint256 amount1;
uint256 minSwapPrice;
uint256 maxSwapPrice;
bool wrap;
bool swap;
address to;
uint256 gasLimit;
uint32 submitDeadline;
}
function deposit(
Data storage data,
DepositParams calldata depositParams,
TokenShares.Data storage tokenShares
) external {
{
uint256 token0TransferCost = getTransferGasCost(depositParams.token0);
uint256 token1TransferCost = getTransferGasCost(depositParams.token1);
checkOrderParams(
depositParams.to,
depositParams.gasLimit,
depositParams.submitDeadline,
ORDER_BASE_COST.add(token0TransferCost).add(token1TransferCost)
);
}
require(depositParams.amount0 != 0 || depositParams.amount1 != 0, 'OS25');
(address pairAddress, bool inverted) = getPair(depositParams.token0, depositParams.token1);
require(!getDepositDisabled(data, pairAddress), 'OS46');
{
uint256 value = msg.value;
if (depositParams.wrap) {
if (depositParams.token0 == TokenShares.WETH_ADDRESS) {
value = msg.value.sub(depositParams.amount0, 'OS1E');
} else if (depositParams.token1 == TokenShares.WETH_ADDRESS) {
value = msg.value.sub(depositParams.amount1, 'OS1E');
}
}
allocateGasRefund(data, value, depositParams.gasLimit);
}
uint256 shares0 = tokenShares.amountToShares(
inverted ? depositParams.token1 : depositParams.token0,
inverted ? depositParams.amount1 : depositParams.amount0,
depositParams.wrap
);
uint256 shares1 = tokenShares.amountToShares(
inverted ? depositParams.token0 : depositParams.token1,
inverted ? depositParams.amount0 : depositParams.amount1,
depositParams.wrap
);
(uint256 priceAccumulator, uint256 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo();
Order memory order = Order(
0,
OrderType.Deposit,
inverted,
timestamp + DELAY,
depositParams.wrap,
timestamp,
depositParams.gasLimit,
data.gasPrice,
0,
shares0,
shares1,
inverted ? depositParams.token1 : depositParams.token0,
inverted ? depositParams.token0 : depositParams.token1,
depositParams.to,
depositParams.minSwapPrice,
depositParams.maxSwapPrice,
depositParams.swap,
priceAccumulator,
inverted ? depositParams.amount1 : depositParams.amount0,
inverted ? depositParams.amount0 : depositParams.amount1
);
enqueueOrder(data, order);
emit DepositEnqueued(order.orderId, order);
}
struct WithdrawParams {
address token0;
address token1;
uint256 liquidity;
uint256 amount0Min;
uint256 amount1Min;
bool unwrap;
address to;
uint256 gasLimit;
uint32 submitDeadline;
}
function withdraw(Data storage data, WithdrawParams calldata withdrawParams) external {
(address pair, bool inverted) = getPair(withdrawParams.token0, withdrawParams.token1);
require(!getWithdrawDisabled(data, pair), 'OS0A');
checkOrderParams(
withdrawParams.to,
withdrawParams.gasLimit,
withdrawParams.submitDeadline,
ORDER_BASE_COST.add(PAIR_TRANSFER_COST)
);
require(withdrawParams.liquidity != 0, 'OS22');
allocateGasRefund(data, msg.value, withdrawParams.gasLimit);
pair.safeTransferFrom(msg.sender, address(this), withdrawParams.liquidity);
Order memory order = Order(
0,
OrderType.Withdraw,
inverted,
block.timestamp + DELAY,
withdrawParams.unwrap,
0,
withdrawParams.gasLimit,
data.gasPrice,
withdrawParams.liquidity,
inverted ? withdrawParams.amount1Min : withdrawParams.amount0Min,
inverted ? withdrawParams.amount0Min : withdrawParams.amount1Min,
inverted ? withdrawParams.token1 : withdrawParams.token0,
inverted ? withdrawParams.token0 : withdrawParams.token1,
withdrawParams.to,
0,
0,
false,
0,
0,
0
);
enqueueOrder(data, order);
emit WithdrawEnqueued(order.orderId, order);
}
struct SellParams {
address tokenIn;
address tokenOut;
uint256 amountIn;
uint256 amountOutMin;
bool wrapUnwrap;
address to;
uint256 gasLimit;
uint32 submitDeadline;
}
function sell(
Data storage data,
SellParams calldata sellParams,
TokenShares.Data storage tokenShares
) external {
uint256 tokenTransferCost = getTransferGasCost(sellParams.tokenIn);
checkOrderParams(
sellParams.to,
sellParams.gasLimit,
sellParams.submitDeadline,
ORDER_BASE_COST.add(tokenTransferCost)
);
(address pairAddress, bool inverted) = sellHelper(data, sellParams);
(uint256 priceAccumulator, uint256 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo();
uint256 shares = tokenShares.amountToShares(sellParams.tokenIn, sellParams.amountIn, sellParams.wrapUnwrap);
Order memory order = Order(
0,
OrderType.Sell,
inverted,
timestamp + DELAY,
sellParams.wrapUnwrap,
timestamp,
sellParams.gasLimit,
data.gasPrice,
0,
shares,
sellParams.amountOutMin,
sellParams.tokenIn,
sellParams.tokenOut,
sellParams.to,
0,
0,
false,
priceAccumulator,
sellParams.amountIn,
0
);
enqueueOrder(data, order);
emit SellEnqueued(order.orderId, order);
}
function relayerSell(
Data storage data,
SellParams calldata sellParams,
TokenShares.Data storage tokenShares
) external {
checkOrderParams(sellParams.to, sellParams.gasLimit, sellParams.submitDeadline, ORDER_BASE_COST);
(, bool inverted) = sellHelper(data, sellParams);
uint256 shares = tokenShares.amountToSharesWithoutTransfer(
sellParams.tokenIn,
sellParams.amountIn,
sellParams.wrapUnwrap
);
Order memory order = Order(
0,
OrderType.Sell,
inverted,
block.timestamp + DELAY,
false,
block.timestamp,
sellParams.gasLimit,
data.gasPrice,
0,
shares,
sellParams.amountOutMin,
sellParams.tokenIn,
sellParams.tokenOut,
sellParams.to,
0,
0,
false,
0,
sellParams.amountIn,
0
);
enqueueOrder(data, order);
emit SellEnqueued(order.orderId, order);
}
function sellHelper(Data storage data, SellParams calldata sellParams)
internal
returns (address pairAddress, bool inverted)
{
require(sellParams.amountIn != 0, 'OS24');
(pairAddress, inverted) = getPair(sellParams.tokenIn, sellParams.tokenOut);
require(!getSellDisabled(data, pairAddress), 'OS13');
uint256 value = msg.value;
if (sellParams.wrapUnwrap && sellParams.tokenIn == TokenShares.WETH_ADDRESS) {
value = msg.value.sub(sellParams.amountIn, 'OS1E');
}
allocateGasRefund(data, value, sellParams.gasLimit);
}
struct BuyParams {
address tokenIn;
address tokenOut;
uint256 amountInMax;
uint256 amountOut;
bool wrapUnwrap;
address to;
uint256 gasLimit;
uint32 submitDeadline;
}
function buy(
Data storage data,
BuyParams calldata buyParams,
TokenShares.Data storage tokenShares
) external {
uint256 tokenTransferCost = getTransferGasCost(buyParams.tokenIn);
checkOrderParams(
buyParams.to,
buyParams.gasLimit,
buyParams.submitDeadline,
ORDER_BASE_COST.add(tokenTransferCost)
);
require(buyParams.amountOut != 0, 'OS23');
(address pairAddress, bool inverted) = getPair(buyParams.tokenIn, buyParams.tokenOut);
require(!getBuyDisabled(data, pairAddress), 'OS49');
uint256 value = msg.value;
if (buyParams.tokenIn == TokenShares.WETH_ADDRESS && buyParams.wrapUnwrap) {
value = msg.value.sub(buyParams.amountInMax, 'OS1E');
}
allocateGasRefund(data, value, buyParams.gasLimit);
uint256 shares = tokenShares.amountToShares(buyParams.tokenIn, buyParams.amountInMax, buyParams.wrapUnwrap);
(uint256 priceAccumulator, uint256 timestamp) = ITwapOracle(ITwapPair(pairAddress).oracle()).getPriceInfo();
Order memory order = Order(
0,
OrderType.Buy,
inverted,
timestamp + DELAY,
buyParams.wrapUnwrap,
timestamp,
buyParams.gasLimit,
data.gasPrice,
0,
shares,
buyParams.amountOut,
buyParams.tokenIn,
buyParams.tokenOut,
buyParams.to,
0,
0,
false,
priceAccumulator,
buyParams.amountInMax,
0
);
enqueueOrder(data, order);
emit BuyEnqueued(order.orderId, order);
}
function checkOrderParams(
address to,
uint256 gasLimit,
uint32 submitDeadline,
uint256 minGasLimit
) private view {
require(submitDeadline >= block.timestamp, 'OS04');
require(gasLimit <= MAX_GAS_LIMIT, 'OS3E');
require(gasLimit >= minGasLimit, 'OS3D');
require(to != address(0), 'OS26');
}
function allocateGasRefund(
Data storage data,
uint256 value,
uint256 gasLimit
) private returns (uint256 futureFee) {
futureFee = data.gasPrice.mul(gasLimit);
require(value >= futureFee, 'OS1E');
if (value > futureFee) {
TransferHelper.safeTransferETH(
msg.sender,
value.sub(futureFee),
getTransferGasCost(NATIVE_CURRENCY_SENTINEL)
);
}
}
function updateGasPrice(Data storage data, uint256 gasUsed) external {
uint256 scale = Math.min(gasUsed, MAX_GAS_PRICE_IMPACT);
data.gasPrice = data.gasPrice.mul(GAS_PRICE_INERTIA.sub(scale)).add(tx.gasprice.mul(scale)).div(
GAS_PRICE_INERTIA
);
}
function refundLiquidity(
address pair,
address to,
uint256 liquidity,
bytes4 selector
) internal returns (bool) {
if (liquidity == 0) {
return true;
}
(bool success, bytes memory data) = address(this).call{ gas: PAIR_TRANSFER_COST }(
abi.encodeWithSelector(selector, pair, to, liquidity, false)
);
if (!success) {
emit RefundFailed(to, pair, liquidity, data);
}
return success;
}
function dequeueOrder(Data storage data, uint256 orderId) internal {
++data.lastProcessedOrderId;
require(orderId == data.lastProcessedOrderId, 'OS72');
}
function forgetOrder(Data storage data, uint256 orderId) internal {
delete data.orderQueue[orderId];
}
function forgetLastProcessedOrder(Data storage data) internal {
delete data.orderQueue[data.lastProcessedOrderId];
}
function getOrderDigest(Order memory order) internal pure returns (bytes32) {
bytes memory partialOrderData = abi.encodePacked(
order.orderId,
order.orderType,
order.inverted,
order.validAfterTimestamp,
order.unwrap,
order.timestamp,
order.gasLimit,
order.gasPrice,
order.liquidity,
order.value0,
order.value1,
order.token0,
order.token1,
order.to
);
return
keccak256(
abi.encodePacked(
partialOrderData,
order.minSwapPrice,
order.maxSwapPrice,
order.swap,
order.priceAccumulator,
order.amountLimit0,
order.amountLimit1
)
);
}
function verifyOrder(Data storage data, Order memory order) external view {
require(getOrderDigest(order) == data.orderQueue[order.orderId], 'OS71');
}
function getTransferGasCost(address token) internal pure returns (uint256) {
if (token == NATIVE_CURRENCY_SENTINEL) return ETHER_TRANSFER_CALL_COST;
if (token == 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48) return 70000;
return 60000;
}
}
文件 14 的 18:SafeMath.sol
pragma solidity 0.7.6;
library SafeMath {
int256 private constant _INT256_MIN = -2**255;
function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x + y) >= x, 'SM4E');
}
function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = sub(x, y, 'SM12');
}
function sub(
uint256 x,
uint256 y,
string memory message
) internal pure returns (uint256 z) {
require((z = x - y) <= x, message);
}
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x, 'SM2A');
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, 'SM43');
return a / b;
}
function ceil_div(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = div(a, b);
if (a != mul(b, c)) {
return add(c, 1);
}
}
function toUint32(uint256 n) internal pure returns (uint32) {
require(n <= type(uint32).max, 'SM50');
return uint32(n);
}
function toUint64(uint256 n) internal pure returns (uint64) {
require(n <= type(uint64).max, 'SM54');
return uint64(n);
}
function toUint112(uint256 n) internal pure returns (uint112) {
require(n <= type(uint112).max, 'SM51');
return uint112(n);
}
function toInt256(uint256 unsigned) internal pure returns (int256 signed) {
require(unsigned <= uint256(type(int256).max), 'SM34');
signed = int256(unsigned);
}
function add(int256 a, int256 b) internal pure returns (int256 c) {
c = a + b;
require((b >= 0 && c >= a) || (b < 0 && c < a), 'SM4D');
}
function sub(int256 a, int256 b) internal pure returns (int256 c) {
c = a - b;
require((b >= 0 && c <= a) || (b < 0 && c > a), 'SM11');
}
function mul(int256 a, int256 b) internal pure returns (int256 c) {
if (a == 0) {
return 0;
}
require(!(a == -1 && b == _INT256_MIN), 'SM29');
c = a * b;
require(c / a == b, 'SM29');
}
function div(int256 a, int256 b) internal pure returns (int256) {
require(b != 0, 'SM43');
require(!(b == -1 && a == _INT256_MIN), 'SM42');
return a / b;
}
function neg_floor_div(int256 a, int256 b) internal pure returns (int256 c) {
c = div(a, b);
if ((a < 0 && b > 0) || (a >= 0 && b < 0)) {
if (a != mul(b, c)) {
c = sub(c, 1);
}
}
}
}
文件 15 的 18:TokenShares.sol
pragma solidity 0.7.6;
import '../interfaces/IERC20.sol';
import '../interfaces/IWETH.sol';
import './SafeMath.sol';
import './TransferHelper.sol';
library TokenShares {
using SafeMath for uint256;
using TransferHelper for address;
uint256 private constant PRECISION = 10**18;
uint256 private constant TOLERANCE = 10**18 + 10**16;
uint256 private constant TOTAL_SHARES_PRECISION = 10**18;
event UnwrapFailed(address to, uint256 amount);
address public constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
struct Data {
mapping(address => uint256) totalShares;
}
function sharesToAmount(
Data storage data,
address token,
uint256 share,
uint256 amountLimit,
address refundTo
) external returns (uint256) {
if (share == 0) {
return 0;
}
if (token == WETH_ADDRESS || isNonRebasing(token)) {
return share;
}
uint256 totalTokenShares = data.totalShares[token];
require(totalTokenShares >= share, 'TS3A');
uint256 balance = IERC20(token).balanceOf(address(this));
uint256 value = balance.mul(share).div(totalTokenShares);
data.totalShares[token] = totalTokenShares.sub(share);
if (amountLimit > 0) {
uint256 amountLimitWithTolerance = amountLimit.mul(TOLERANCE).div(PRECISION);
if (value > amountLimitWithTolerance) {
TransferHelper.safeTransfer(token, refundTo, value.sub(amountLimitWithTolerance));
return amountLimitWithTolerance;
}
}
return value;
}
function amountToShares(
Data storage data,
address token,
uint256 amount,
bool wrap
) external returns (uint256) {
if (amount == 0) {
return 0;
}
if (token == WETH_ADDRESS) {
if (wrap) {
require(msg.value >= amount, 'TS03');
IWETH(token).deposit{ value: amount }();
} else {
token.safeTransferFrom(msg.sender, address(this), amount);
}
return amount;
} else if (isNonRebasing(token)) {
token.safeTransferFrom(msg.sender, address(this), amount);
return amount;
} else {
uint256 balanceBefore = IERC20(token).balanceOf(address(this));
token.safeTransferFrom(msg.sender, address(this), amount);
uint256 balanceAfter = IERC20(token).balanceOf(address(this));
return amountToSharesHelper(data, token, balanceBefore, balanceAfter);
}
}
function amountToSharesWithoutTransfer(
Data storage data,
address token,
uint256 amount,
bool wrap
) external returns (uint256) {
if (token == WETH_ADDRESS) {
if (wrap) {
IWETH(token).deposit{ value: amount }();
}
return amount;
} else if (isNonRebasing(token)) {
return amount;
} else {
uint256 balanceAfter = IERC20(token).balanceOf(address(this));
uint256 balanceBefore = balanceAfter.sub(amount);
return amountToSharesHelper(data, token, balanceBefore, balanceAfter);
}
}
function amountToSharesHelper(
Data storage data,
address token,
uint256 balanceBefore,
uint256 balanceAfter
) internal returns (uint256) {
uint256 totalTokenShares = data.totalShares[token];
require(balanceBefore > 0 || totalTokenShares == 0, 'TS30');
require(balanceAfter > balanceBefore, 'TS2C');
if (balanceBefore > 0) {
if (totalTokenShares == 0) {
totalTokenShares = balanceBefore.mul(TOTAL_SHARES_PRECISION);
}
uint256 newShares = totalTokenShares.mul(balanceAfter).div(balanceBefore);
require(balanceAfter < type(uint256).max.div(newShares), 'TS73');
data.totalShares[token] = newShares;
return newShares - totalTokenShares;
} else {
totalTokenShares = balanceAfter.mul(TOTAL_SHARES_PRECISION);
require(totalTokenShares < type(uint256).max.div(totalTokenShares), 'TS73');
data.totalShares[token] = totalTokenShares;
return totalTokenShares;
}
}
function onUnwrapFailed(address to, uint256 amount) external {
emit UnwrapFailed(to, amount);
IWETH(WETH_ADDRESS).deposit{ value: amount }();
TransferHelper.safeTransfer(WETH_ADDRESS, to, amount);
}
function isNonRebasing(address token) internal pure returns (bool) {
if (token == 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) return true;
if (token == 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48) return true;
if (token == 0xdAC17F958D2ee523a2206206994597C13D831ec7) return true;
if (token == 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599) return true;
return false;
}
}
文件 16 的 18:TransferHelper.sol
pragma solidity 0.7.6;
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 value
) internal {
(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 {
(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 {
(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 }('');
}
}
文件 17 的 18:TwapDelay.sol
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';
import './libraries/ExecutionHelper.sol';
import './interfaces/ITwapFactoryGovernor.sol';
contract TwapDelay is ITwapDelay {
using SafeMath for uint256;
using Orders for Orders.Data;
using TokenShares for TokenShares.Data;
Orders.Data internal orders;
TokenShares.Data internal tokenShares;
uint256 private constant ORDER_CANCEL_TIME = 24 hours;
uint256 private constant BOT_EXECUTION_TIME = 20 minutes;
address public override owner;
address public override factoryGovernor;
address public constant RELAYER_ADDRESS = 0xd17b3c9784510E33cD5B87b490E79253BcD81e2E;
mapping(address => bool) public override isBot;
constructor(address _factoryGovernor, address _bot) {
_setOwner(msg.sender);
_setFactoryGovernor(_factoryGovernor);
_setBot(_bot, true);
orders.gasPrice = tx.gasprice;
_emitEventWithDefaults();
}
function getTransferGasCost(address token) external pure override returns (uint256 gasCost) {
return Orders.getTransferGasCost(token);
}
function getDepositDisabled(address pair) external view override returns (bool) {
return orders.getDepositDisabled(pair);
}
function getWithdrawDisabled(address pair) external view override returns (bool) {
return orders.getWithdrawDisabled(pair);
}
function getBuyDisabled(address pair) external view override returns (bool) {
return orders.getBuyDisabled(pair);
}
function getSellDisabled(address pair) external view override returns (bool) {
return orders.getSellDisabled(pair);
}
function getOrderStatus(uint256 orderId, uint256 validAfterTimestamp)
external
view
override
returns (Orders.OrderStatus)
{
return orders.getOrderStatus(orderId, validAfterTimestamp);
}
uint256 private locked;
modifier lock() {
require(locked == 0, 'TD06');
locked = 1;
_;
locked = 0;
}
function factory() external pure override returns (address) {
return Orders.FACTORY_ADDRESS;
}
function totalShares(address token) external view override returns (uint256) {
return tokenShares.totalShares[token];
}
function weth() external pure override returns (address) {
return TokenShares.WETH_ADDRESS;
}
function relayer() external pure override returns (address) {
return RELAYER_ADDRESS;
}
function isNonRebasingToken(address token) external pure override returns (bool) {
return TokenShares.isNonRebasing(token);
}
function delay() external pure override returns (uint256) {
return Orders.DELAY;
}
function lastProcessedOrderId() external view returns (uint256) {
return orders.lastProcessedOrderId;
}
function newestOrderId() external view returns (uint256) {
return orders.newestOrderId;
}
function isOrderCanceled(uint256 orderId) external view returns (bool) {
return orders.canceled[orderId];
}
function maxGasLimit() external pure override returns (uint256) {
return Orders.MAX_GAS_LIMIT;
}
function maxGasPriceImpact() external pure override returns (uint256) {
return Orders.MAX_GAS_PRICE_IMPACT;
}
function gasPriceInertia() external pure override returns (uint256) {
return Orders.GAS_PRICE_INERTIA;
}
function gasPrice() external view override returns (uint256) {
return orders.gasPrice;
}
function setOrderTypesDisabled(
address pair,
Orders.OrderType[] calldata orderTypes,
bool disabled
) external override {
require(msg.sender == owner, 'TD00');
orders.setOrderTypesDisabled(pair, orderTypes, disabled);
}
function setOwner(address _owner) external override {
require(msg.sender == owner, 'TD00');
_setOwner(_owner);
}
function _setOwner(address _owner) internal {
require(_owner != owner, 'TD01');
require(_owner != address(0), 'TD02');
owner = _owner;
emit OwnerSet(_owner);
}
function setFactoryGovernor(address _factoryGovernor) external override {
require(msg.sender == owner, 'TD00');
_setFactoryGovernor(_factoryGovernor);
}
function _setFactoryGovernor(address _factoryGovernor) internal {
require(_factoryGovernor != factoryGovernor, 'TD01');
require(_factoryGovernor != address(0), 'TD02');
factoryGovernor = _factoryGovernor;
emit FactoryGovernorSet(_factoryGovernor);
}
function setBot(address _bot, bool _isBot) external override {
require(msg.sender == owner, 'TD00');
_setBot(_bot, _isBot);
}
function _setBot(address _bot, bool _isBot) internal {
require(_isBot != isBot[_bot], 'TD01');
isBot[_bot] = _isBot;
emit BotSet(_bot, _isBot);
}
function deposit(Orders.DepositParams calldata depositParams)
external
payable
override
lock
returns (uint256 orderId)
{
orders.deposit(depositParams, tokenShares);
return orders.newestOrderId;
}
function withdraw(Orders.WithdrawParams calldata withdrawParams)
external
payable
override
lock
returns (uint256 orderId)
{
orders.withdraw(withdrawParams);
return orders.newestOrderId;
}
function sell(Orders.SellParams calldata sellParams) external payable override lock returns (uint256 orderId) {
orders.sell(sellParams, tokenShares);
return orders.newestOrderId;
}
function relayerSell(Orders.SellParams calldata sellParams)
external
payable
override
lock
returns (uint256 orderId)
{
require(msg.sender == RELAYER_ADDRESS, 'TD00');
orders.relayerSell(sellParams, tokenShares);
return orders.newestOrderId;
}
function buy(Orders.BuyParams calldata buyParams) external payable override lock returns (uint256 orderId) {
orders.buy(buyParams, tokenShares);
return orders.newestOrderId;
}
function execute(Orders.Order[] calldata _orders) external payable override lock {
uint256 ordersLength = _orders.length;
uint256 gasBefore = gasleft();
bool orderExecuted;
bool senderCanExecute = isBot[msg.sender] || isBot[address(0)];
for (uint256 i; i < ordersLength; ++i) {
if (_orders[i].orderId <= orders.lastProcessedOrderId) {
continue;
}
if (orders.canceled[_orders[i].orderId]) {
orders.dequeueOrder(_orders[i].orderId);
continue;
}
orders.verifyOrder(_orders[i]);
uint256 validAfterTimestamp = _orders[i].validAfterTimestamp;
if (validAfterTimestamp >= block.timestamp) {
break;
}
require(senderCanExecute || block.timestamp >= validAfterTimestamp + BOT_EXECUTION_TIME, 'TD00');
orderExecuted = true;
if (_orders[i].orderType == Orders.OrderType.Deposit) {
executeDeposit(_orders[i]);
} else if (_orders[i].orderType == Orders.OrderType.Withdraw) {
executeWithdraw(_orders[i]);
} else if (_orders[i].orderType == Orders.OrderType.Sell) {
executeSell(_orders[i]);
} else if (_orders[i].orderType == Orders.OrderType.Buy) {
executeBuy(_orders[i]);
}
}
if (orderExecuted) {
orders.updateGasPrice(gasBefore.sub(gasleft()));
}
}
function executeDeposit(Orders.Order calldata order) internal {
uint256 gasStart = gasleft();
orders.dequeueOrder(order.orderId);
(bool executionSuccess, bytes memory data) = address(this).call{
gas: order.gasLimit.sub(
Orders.ORDER_BASE_COST.add(Orders.getTransferGasCost(order.token0)).add(
Orders.getTransferGasCost(order.token1)
)
)
}(abi.encodeWithSelector(this._executeDeposit.selector, order));
bool refundSuccess = true;
if (!executionSuccess) {
refundSuccess = refundTokens(
order.to,
order.token0,
order.value0,
order.token1,
order.value1,
order.unwrap
);
}
finalizeOrder(refundSuccess);
(uint256 gasUsed, uint256 ethRefund) = refund(order.gasLimit, order.gasPrice, gasStart, order.to);
emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund);
}
function executeWithdraw(Orders.Order calldata order) internal {
uint256 gasStart = gasleft();
orders.dequeueOrder(order.orderId);
(bool executionSuccess, bytes memory data) = address(this).call{
gas: order.gasLimit.sub(Orders.ORDER_BASE_COST.add(Orders.PAIR_TRANSFER_COST))
}(abi.encodeWithSelector(this._executeWithdraw.selector, order));
bool refundSuccess = true;
if (!executionSuccess) {
(address pair, ) = Orders.getPair(order.token0, order.token1);
refundSuccess = Orders.refundLiquidity(pair, order.to, order.liquidity, this._refundLiquidity.selector);
}
finalizeOrder(refundSuccess);
(uint256 gasUsed, uint256 ethRefund) = refund(order.gasLimit, order.gasPrice, gasStart, order.to);
emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund);
}
function executeSell(Orders.Order calldata order) internal {
uint256 gasStart = gasleft();
orders.dequeueOrder(order.orderId);
(bool executionSuccess, bytes memory data) = address(this).call{
gas: order.gasLimit.sub(Orders.ORDER_BASE_COST.add(Orders.getTransferGasCost(order.token0)))
}(abi.encodeWithSelector(this._executeSell.selector, order));
bool refundSuccess = true;
if (!executionSuccess) {
refundSuccess = refundToken(order.token0, order.to, order.value0, order.unwrap);
}
finalizeOrder(refundSuccess);
(uint256 gasUsed, uint256 ethRefund) = refund(order.gasLimit, order.gasPrice, gasStart, order.to);
emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund);
}
function executeBuy(Orders.Order calldata order) internal {
uint256 gasStart = gasleft();
orders.dequeueOrder(order.orderId);
(bool executionSuccess, bytes memory data) = address(this).call{
gas: order.gasLimit.sub(Orders.ORDER_BASE_COST.add(Orders.getTransferGasCost(order.token0)))
}(abi.encodeWithSelector(this._executeBuy.selector, order));
bool refundSuccess = true;
if (!executionSuccess) {
refundSuccess = refundToken(order.token0, order.to, order.value0, order.unwrap);
}
finalizeOrder(refundSuccess);
(uint256 gasUsed, uint256 ethRefund) = refund(order.gasLimit, order.gasPrice, gasStart, order.to);
emit OrderExecuted(orders.lastProcessedOrderId, executionSuccess, data, gasUsed, ethRefund);
}
function finalizeOrder(bool refundSuccess) private {
if (!refundSuccess) {
orders.markRefundFailed();
} else {
orders.forgetLastProcessedOrder();
}
}
function refund(
uint256 gasLimit,
uint256 gasPriceInOrder,
uint256 gasStart,
address to
) private returns (uint256 gasUsed, uint256 leftOver) {
uint256 feeCollected = gasLimit.mul(gasPriceInOrder);
gasUsed = gasStart.sub(gasleft()).add(Orders.REFUND_BASE_COST);
uint256 actualRefund = Math.min(feeCollected, gasUsed.mul(orders.gasPrice));
leftOver = feeCollected.sub(actualRefund);
require(refundEth(msg.sender, actualRefund), 'TD40');
refundEth(payable(to), leftOver);
}
function refundEth(address payable to, uint256 value) internal returns (bool success) {
if (value == 0) {
return true;
}
success = TransferHelper.transferETH(to, value, Orders.getTransferGasCost(Orders.NATIVE_CURRENCY_SENTINEL));
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.getTransferGasCost(token) }(
abi.encodeWithSelector(this._refundToken.selector, token, to, share, unwrap)
);
if (!success) {
emit Orders.RefundFailed(to, token, share, data);
}
return success;
}
function refundTokens(
address to,
address token0,
uint256 share0,
address token1,
uint256 share1,
bool unwrap
) private returns (bool) {
(bool success, bytes memory data) = address(this).call{
gas: Orders.getTransferGasCost(token0).add(Orders.getTransferGasCost(token1))
}(abi.encodeWithSelector(this._refundTokens.selector, to, token0, share0, token1, share1, unwrap));
if (!success) {
emit Orders.RefundFailed(to, token0, share0, data);
emit Orders.RefundFailed(to, token1, share1, data);
}
return success;
}
function _refundTokens(
address to,
address token0,
uint256 share0,
address token1,
uint256 share1,
bool unwrap
) external payable {
_refundToken(token0, to, share0, unwrap);
_refundToken(token1, to, share1, unwrap);
}
function _refundToken(
address token,
address to,
uint256 share,
bool unwrap
) public payable {
require(msg.sender == address(this), 'TD00');
if (token == TokenShares.WETH_ADDRESS && unwrap) {
uint256 amount = tokenShares.sharesToAmount(token, share, 0, to);
IWETH(TokenShares.WETH_ADDRESS).withdraw(amount);
TransferHelper.safeTransferETH(to, amount, Orders.getTransferGasCost(Orders.NATIVE_CURRENCY_SENTINEL));
} else {
TransferHelper.safeTransfer(token, to, tokenShares.sharesToAmount(token, share, 0, to));
}
}
function _refundLiquidity(
address pair,
address to,
uint256 liquidity
) external payable {
require(msg.sender == address(this), 'TD00');
return TransferHelper.safeTransfer(pair, to, liquidity);
}
function _executeDeposit(Orders.Order calldata order) external payable {
require(msg.sender == address(this), 'TD00');
(address pairAddress, ) = Orders.getPair(order.token0, order.token1);
ITwapPair(pairAddress).sync();
ITwapFactoryGovernor(factoryGovernor).distributeFees(order.token0, order.token1, pairAddress);
ITwapPair(pairAddress).sync();
ExecutionHelper.executeDeposit(order, pairAddress, getTolerance(pairAddress), tokenShares);
}
function _executeWithdraw(Orders.Order calldata order) external payable {
require(msg.sender == address(this), 'TD00');
(address pairAddress, ) = Orders.getPair(order.token0, order.token1);
ITwapPair(pairAddress).sync();
ITwapFactoryGovernor(factoryGovernor).distributeFees(order.token0, order.token1, pairAddress);
ITwapPair(pairAddress).sync();
ExecutionHelper.executeWithdraw(order);
}
function _executeBuy(Orders.Order calldata order) external payable {
require(msg.sender == address(this), 'TD00');
(address pairAddress, ) = Orders.getPair(order.token0, order.token1);
ExecutionHelper.ExecuteBuySellParams memory orderParams;
orderParams.order = order;
orderParams.pairAddress = pairAddress;
orderParams.pairTolerance = getTolerance(pairAddress);
ITwapPair(pairAddress).sync();
ExecutionHelper.executeBuy(orderParams, tokenShares);
}
function _executeSell(Orders.Order calldata order) external payable {
require(msg.sender == address(this), 'TD00');
(address pairAddress, ) = Orders.getPair(order.token0, order.token1);
ExecutionHelper.ExecuteBuySellParams memory orderParams;
orderParams.order = order;
orderParams.pairAddress = pairAddress;
orderParams.pairTolerance = getTolerance(pairAddress);
ITwapPair(pairAddress).sync();
ExecutionHelper.executeSell(orderParams, tokenShares);
}
function performRefund(Orders.Order calldata order, bool shouldRefundEth) internal {
bool canOwnerRefund = order.validAfterTimestamp.add(365 days) < block.timestamp;
if (order.orderType == Orders.OrderType.Deposit) {
address to = canOwnerRefund ? owner : order.to;
require(refundTokens(to, order.token0, order.value0, order.token1, order.value1, order.unwrap), 'TD14');
if (shouldRefundEth) {
require(refundEth(payable(to), order.gasPrice.mul(order.gasLimit)), 'TD40');
}
} else if (order.orderType == Orders.OrderType.Withdraw) {
(address pair, ) = Orders.getPair(order.token0, order.token1);
address to = canOwnerRefund ? owner : order.to;
require(Orders.refundLiquidity(pair, to, order.liquidity, this._refundLiquidity.selector), 'TD14');
if (shouldRefundEth) {
require(refundEth(payable(to), order.gasPrice.mul(order.gasLimit)), 'TD40');
}
} else if (order.orderType == Orders.OrderType.Sell) {
address to = canOwnerRefund ? owner : order.to;
require(refundToken(order.token0, to, order.value0, order.unwrap), 'TD14');
if (shouldRefundEth) {
require(refundEth(payable(to), order.gasPrice.mul(order.gasLimit)), 'TD40');
}
} else if (order.orderType == Orders.OrderType.Buy) {
address to = canOwnerRefund ? owner : order.to;
require(refundToken(order.token0, to, order.value0, order.unwrap), 'TD14');
if (shouldRefundEth) {
require(refundEth(payable(to), order.gasPrice.mul(order.gasLimit)), 'TD40');
}
} else {
return;
}
orders.forgetOrder(order.orderId);
}
function retryRefund(Orders.Order calldata order) external override lock {
orders.verifyOrder(order);
require(orders.refundFailed[order.orderId], 'TD21');
performRefund(order, false);
}
function cancelOrder(Orders.Order calldata order) external override lock {
orders.verifyOrder(order);
require(
orders.getOrderStatus(order.orderId, order.validAfterTimestamp) == Orders.OrderStatus.EnqueuedReady,
'TD52'
);
require(order.validAfterTimestamp.sub(Orders.DELAY).add(ORDER_CANCEL_TIME) < block.timestamp, 'TD1C');
orders.canceled[order.orderId] = true;
performRefund(order, true);
}
function syncPair(address token0, address token1) external override returns (address pairAddress) {
require(msg.sender == factoryGovernor, 'TD00');
(pairAddress, ) = Orders.getPair(token0, token1);
ITwapPair(pairAddress).sync();
}
function _emitEventWithDefaults() internal {
emit MaxGasLimitSet(Orders.MAX_GAS_LIMIT);
emit GasPriceInertiaSet(Orders.GAS_PRICE_INERTIA);
emit MaxGasPriceImpactSet(Orders.MAX_GAS_PRICE_IMPACT);
emit DelaySet(Orders.DELAY);
emit RelayerSet(RELAYER_ADDRESS);
emit ToleranceSet(0x2fe16Dd18bba26e457B7dD2080d5674312b026a2, 0);
emit ToleranceSet(0x048f0e7ea2CFD522a4a058D1b1bDd574A0486c46, 0);
emit ToleranceSet(0x37F6dF71b40c50b2038329CaBf5FDa3682Df1ebF, 0);
emit ToleranceSet(0x6ec472b613012a492693697FA551420E60567eA7, 0);
emit ToleranceSet(0x43f0E5f2304F261DfA5359a0b74Ff030E498D904, 0);
emit ToleranceSet(0xD66f214fB49f81Ac5610e0339A351D7e1c67c35e, 0);
emit ToleranceSet(0xD4d2140eD70DCF8794A986F0CFD07560ee738C71, 4);
emit TransferGasCostSet(Orders.NATIVE_CURRENCY_SENTINEL, Orders.ETHER_TRANSFER_CALL_COST);
emit TransferGasCostSet(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, 60000);
emit TransferGasCostSet(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48, 70000);
emit TransferGasCostSet(0xdAC17F958D2ee523a2206206994597C13D831ec7, 60000);
emit TransferGasCostSet(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599, 60000);
emit TransferGasCostSet(0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B, 60000);
emit TransferGasCostSet(0x6B3595068778DD592e39A122f4f5a5cF09C90fE2, 60000);
emit NonRebasingTokenSet(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, true);
emit NonRebasingTokenSet(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48, true);
emit NonRebasingTokenSet(0xdAC17F958D2ee523a2206206994597C13D831ec7, true);
emit NonRebasingTokenSet(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599, true);
emit NonRebasingTokenSet(0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B, false);
emit NonRebasingTokenSet(0x6B3595068778DD592e39A122f4f5a5cF09C90fE2, false);
}
function getTolerance(address pair) public virtual view override returns (uint16 tolerance) {
if (pair == 0xD4d2140eD70DCF8794A986F0CFD07560ee738C71) return 4;
return 0;
}
receive() external payable {}
}
文件 18 的 18:WithdrawHelper.sol
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);
}
}
{
"compilationTarget": {
"contracts/TwapDelay.sol": "TwapDelay"
},
"evmVersion": "istanbul",
"libraries": {
"contracts/libraries/ExecutionHelper.sol:ExecutionHelper": "0xeb244fb424b56ccb96d42bd1983fb0d67037b27e",
"contracts/libraries/Orders.sol:Orders": "0x6b225b3797892c6582a06d17bcfe0a96f0b9087c",
"contracts/libraries/TokenShares.sol:TokenShares": "0xff407b033077b5cabdef809e953cadbe4b322126"
},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_factoryGovernor","type":"address"},{"internalType":"address","name":"_bot","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"bot","type":"address"},{"indexed":false,"internalType":"bool","name":"isBot","type":"bool"}],"name":"BotSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"DelaySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"EthRefund","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"factoryGovernor","type":"address"}],"name":"FactoryGovernorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"gasPriceInertia","type":"uint256"}],"name":"GasPriceInertiaSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxGasLimit","type":"uint256"}],"name":"MaxGasLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxGasPriceImpact","type":"uint256"}],"name":"MaxGasPriceImpactSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"bool","name":"isNonRebasing","type":"bool"}],"name":"NonRebasingTokenSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"gasSpent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ethRefunded","type":"uint256"}],"name":"OrderExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"OwnerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"relayer","type":"address"}],"name":"RelayerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"uint16","name":"amount","type":"uint16"}],"name":"ToleranceSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"gasCost","type":"uint256"}],"name":"TransferGasCostSet","type":"event"},{"inputs":[],"name":"RELAYER_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"inverted","type":"bool"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"_executeBuy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"inverted","type":"bool"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"_executeDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"inverted","type":"bool"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"_executeSell","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"inverted","type":"bool"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"_executeWithdraw","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"name":"_refundLiquidity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"share","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"}],"name":"_refundToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"uint256","name":"share0","type":"uint256"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"share1","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"}],"name":"_refundTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"bool","name":"wrapUnwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.BuyParams","name":"buyParams","type":"tuple"}],"name":"buy","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"inverted","type":"bool"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"wrap","type":"bool"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.DepositParams","name":"depositParams","type":"tuple"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"inverted","type":"bool"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order[]","name":"_orders","type":"tuple[]"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"factoryGovernor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasPriceInertia","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getBuyDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getDepositDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"}],"name":"getOrderStatus","outputs":[{"internalType":"enum Orders.OrderStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getSellDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getTolerance","outputs":[{"internalType":"uint16","name":"tolerance","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTransferGasCost","outputs":[{"internalType":"uint256","name":"gasCost","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"getWithdrawDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isBot","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"isNonRebasingToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"isOrderCanceled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastProcessedOrderId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxGasLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"maxGasPriceImpact","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"newestOrderId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"relayer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"wrapUnwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.SellParams","name":"sellParams","type":"tuple"}],"name":"relayerSell","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"enum Orders.OrderType","name":"orderType","type":"uint8"},{"internalType":"bool","name":"inverted","type":"bool"},{"internalType":"uint256","name":"validAfterTimestamp","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"value0","type":"uint256"},{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minSwapPrice","type":"uint256"},{"internalType":"uint256","name":"maxSwapPrice","type":"uint256"},{"internalType":"bool","name":"swap","type":"bool"},{"internalType":"uint256","name":"priceAccumulator","type":"uint256"},{"internalType":"uint256","name":"amountLimit0","type":"uint256"},{"internalType":"uint256","name":"amountLimit1","type":"uint256"}],"internalType":"struct Orders.Order","name":"order","type":"tuple"}],"name":"retryRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"wrapUnwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.SellParams","name":"sellParams","type":"tuple"}],"name":"sell","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_bot","type":"address"},{"internalType":"bool","name":"_isBot","type":"bool"}],"name":"setBot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_factoryGovernor","type":"address"}],"name":"setFactoryGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"},{"internalType":"enum Orders.OrderType[]","name":"orderTypes","type":"uint8[]"},{"internalType":"bool","name":"disabled","type":"bool"}],"name":"setOrderTypesDisabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"name":"syncPair","outputs":[{"internalType":"address","name":"pairAddress","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint32","name":"submitDeadline","type":"uint32"}],"internalType":"struct Orders.WithdrawParams","name":"withdrawParams","type":"tuple"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]