/
ExampleSwapToPrice.sol
77 lines (65 loc) 路 2.78 KB
/
ExampleSwapToPrice.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
pragma solidity =0.6.6;
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';
import '@uniswap/lib/contracts/libraries/Babylonian.sol';
import '@uniswap/lib/contracts/libraries/TransferHelper.sol';
import '../libraries/UniswapV2LiquidityMathLibrary.sol';
import '../interfaces/IERC20.sol';
import '../interfaces/IUniswapV2Router01.sol';
import '../libraries/SafeMath.sol';
import '../libraries/UniswapV2Library.sol';
contract ExampleSwapToPrice {
using SafeMath for uint256;
IUniswapV2Router01 public immutable router;
address public immutable factory;
constructor(address factory_, IUniswapV2Router01 router_) public {
factory = factory_;
router = router_;
}
// swaps an amount of either token such that the trade is profit-maximizing, given an external true price
// true price is expressed in the ratio of token A to token B
// caller must approve this contract to spend whichever token is intended to be swapped
function swapToPrice(
address tokenA,
address tokenB,
uint256 truePriceTokenA,
uint256 truePriceTokenB,
uint256 maxSpendTokenA,
uint256 maxSpendTokenB,
address to,
uint256 deadline
) public {
// true price is expressed as a ratio, so both values must be non-zero
require(truePriceTokenA != 0 && truePriceTokenB != 0, "ExampleSwapToPrice: ZERO_PRICE");
// caller can specify 0 for either if they wish to swap in only one direction, but not both
require(maxSpendTokenA != 0 || maxSpendTokenB != 0, "ExampleSwapToPrice: ZERO_SPEND");
bool aToB;
uint256 amountIn;
{
(uint256 reserveA, uint256 reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB);
(aToB, amountIn) = UniswapV2LiquidityMathLibrary.computeProfitMaximizingTrade(
truePriceTokenA, truePriceTokenB,
reserveA, reserveB
);
}
require(amountIn > 0, 'ExampleSwapToPrice: ZERO_AMOUNT_IN');
// spend up to the allowance of the token in
uint256 maxSpend = aToB ? maxSpendTokenA : maxSpendTokenB;
if (amountIn > maxSpend) {
amountIn = maxSpend;
}
address tokenIn = aToB ? tokenA : tokenB;
address tokenOut = aToB ? tokenB : tokenA;
TransferHelper.safeTransferFrom(tokenIn, msg.sender, address(this), amountIn);
TransferHelper.safeApprove(tokenIn, address(router), amountIn);
address[] memory path = new address[](2);
path[0] = tokenIn;
path[1] = tokenOut;
router.swapExactTokensForTokens(
amountIn,
0, // amountOutMin: we can skip computing this number because the math is tested
path,
to,
deadline
);
}
}