Q1ngying

今朝梦醒与君别,遥盼春风寄相思

0%

UniswapV2-Rounter

Rounter02

由于 Rounter 是无状态的,且不持有代币余额,因此如有必要,可以安全且无需信任地更换他们。如果发现更有效的智能合约模式,或者需要额外的功能,则可能会发生这种情况。所以 Rounter 有版本号,现在使用的多为 Rounter02 版本。

Code

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
pragma solidity =0.6.6;

import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';
import '@uniswap/lib/contracts/libraries/TransferHelper.sol';

import './interfaces/IUniswapV2Router02.sol';
import './libraries/UniswapV2Library.sol';
import './libraries/SafeMath.sol';
import './interfaces/IERC20.sol';
import './interfaces/IWETH.sol';

contract UniswapV2Router02 is IUniswapV2Router02 {
using SafeMath for uint;

address public immutable override factory;
address public immutable override WETH;

modifier ensure(uint deadline) {
require(deadline >= block.timestamp, 'UniswapV2Router: EXPIRED');
_;
}

constructor(address _factory, address _WETH) public {
factory = _factory;
WETH = _WETH;
}

receive() external payable {
assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract
}

// **** ADD LIQUIDITY ****
function _addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin
) internal virtual returns (uint amountA, uint amountB) {
// create the pair if it doesn't exist yet
if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {
IUniswapV2Factory(factory).createPair(tokenA, tokenB);
}
(uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB);
if (reserveA == 0 && reserveB == 0) {
(amountA, amountB) = (amountADesired, amountBDesired);
} else {
uint amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB);
if (amountBOptimal <= amountBDesired) {
require(amountBOptimal >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
(amountA, amountB) = (amountADesired, amountBOptimal);
} else {
uint amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA);
assert(amountAOptimal <= amountADesired);
require(amountAOptimal >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
(amountA, amountB) = (amountAOptimal, amountBDesired);
}
}
}
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) {
(amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);
TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);
liquidity = IUniswapV2Pair(pair).mint(to);
}
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external virtual override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) {
(amountToken, amountETH) = _addLiquidity(
token,
WETH,
amountTokenDesired,
msg.value,
amountTokenMin,
amountETHMin
);
address pair = UniswapV2Library.pairFor(factory, token, WETH);
TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
IWETH(WETH).deposit{value: amountETH}();
assert(IWETH(WETH).transfer(pair, amountETH));
liquidity = IUniswapV2Pair(pair).mint(to);
// refund dust eth, if any
if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
}

// **** REMOVE LIQUIDITY ****
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountA, uint amountB) {
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
(uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to);
(address token0,) = UniswapV2Library.sortTokens(tokenA, tokenB);
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
require(amountA >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
require(amountB >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
}
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) {
(amountToken, amountETH) = removeLiquidity(
token,
WETH,
liquidity,
amountTokenMin,
amountETHMin,
address(this),
deadline
);
TransferHelper.safeTransfer(token, to, amountToken);
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountA, uint amountB) {
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
uint value = approveMax ? uint(-1) : liquidity;
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
}
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountToken, uint amountETH) {
address pair = UniswapV2Library.pairFor(factory, token, WETH);
uint value = approveMax ? uint(-1) : liquidity;
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
}

// **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) ****
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountETH) {
(, amountETH) = removeLiquidity(
token,
WETH,
liquidity,
amountTokenMin,
amountETHMin,
address(this),
deadline
);
TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountETH) {
address pair = UniswapV2Library.pairFor(factory, token, WETH);
uint value = approveMax ? uint(-1) : liquidity;
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(
token, liquidity, amountTokenMin, amountETHMin, to, deadline
);
}

// **** SWAP ****
// requires the initial amount to have already been sent to the first pair
function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = UniswapV2Library.sortTokens(input, output);
uint amountOut = amounts[i + 1];
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to;
IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output)).swap(
amount0Out, amount1Out, to, new bytes(0)
);
}
}
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, to);
}
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, to);
}
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
virtual
override
payable
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsOut(factory, msg.value, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
}
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
virtual
override
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, address(this));
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
virtual
override
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, address(this));
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
virtual
override
payable
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= msg.value, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
// refund dust eth, if any
if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
}

// **** SWAP (supporting fee-on-transfer tokens) ****
// requires the initial amount to have already been sent to the first pair
function _swapSupportingFeeOnTransferTokens(address[] memory path, address _to) internal virtual {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = UniswapV2Library.sortTokens(input, output);
IUniswapV2Pair pair = IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output));
uint amountInput;
uint amountOutput;
{ // scope to avoid stack too deep errors
(uint reserve0, uint reserve1,) = pair.getReserves();
(uint reserveInput, uint reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
amountInput = IERC20(input).balanceOf(address(pair)).sub(reserveInput);
amountOutput = UniswapV2Library.getAmountOut(amountInput, reserveInput, reserveOutput);
}
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0));
address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to;
pair.swap(amount0Out, amount1Out, to, new bytes(0));
}
}
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external virtual override ensure(deadline) {
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn
);
uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
_swapSupportingFeeOnTransferTokens(path, to);
require(
IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'
);
}
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
)
external
virtual
override
payable
ensure(deadline)
{
require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
uint amountIn = msg.value;
IWETH(WETH).deposit{value: amountIn}();
assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn));
uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
_swapSupportingFeeOnTransferTokens(path, to);
require(
IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'
);
}
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
)
external
virtual
override
ensure(deadline)
{
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn
);
_swapSupportingFeeOnTransferTokens(path, address(this));
uint amountOut = IERC20(WETH).balanceOf(address(this));
require(amountOut >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
IWETH(WETH).withdraw(amountOut);
TransferHelper.safeTransferETH(to, amountOut);
}

// **** LIBRARY FUNCTIONS ****
function quote(uint amountA, uint reserveA, uint reserveB) public pure virtual override returns (uint amountB) {
return UniswapV2Library.quote(amountA, reserveA, reserveB);
}

function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut)
public
pure
virtual
override
returns (uint amountOut)
{
return UniswapV2Library.getAmountOut(amountIn, reserveIn, reserveOut);
}

function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut)
public
pure
virtual
override
returns (uint amountIn)
{
return UniswapV2Library.getAmountIn(amountOut, reserveIn, reserveOut);
}

function getAmountsOut(uint amountIn, address[] memory path)
public
view
virtual
override
returns (uint[] memory amounts)
{
return UniswapV2Library.getAmountsOut(factory, amountIn, path);
}

function getAmountsIn(uint amountOut, address[] memory path)
public
view
virtual
override
returns (uint[] memory amounts)
{
return UniswapV2Library.getAmountsIn(factory, amountOut, path);
}
}

Read-Only Function

factory

1
function factory() external pure returns (address);

返回 factory 的地址。

WETH

1
function WETH() external pure returns (address);

返回目前网络上规范的 WETH 地址。

quote

1
function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB);

给定一些资产金额和储备,返回代表等值的其他资产的金额。

  • 对于在调用 mint 之前计算最佳代币的数量很有用

getAmountOut

1
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut);

给定输入资产金额,返回给定储备的其他资产的最大输出金额(考虑费用)

getAmountIn

1
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn);

返回购买给定储备的给定输出资产金额(考虑费用)所需的最小资产金额。

getAmountsOut

1
function getAmountsOut(uint amountIn, address[] memory path) internal view returns (uint[] memory amounts);

给定输入资产数量和一组代币地址,通过一次为路径中的每组代币调用 getReserves 并使用它们调用 getAmountOut 来计算所有后续最大输出代币数量。

  • 对于在调用交换之前计算最佳代币数量很有用

getAmountsIn

1
function getAMountsIn(address factorym uint amountOut, address[] memory path) internal view returns(uint[] memory amounts);

给定一个输出资产数量和一组代币地址,通过依次为路径中的每对代币地址调用 getReserves 来计算所有前面的最小输入代币数量,并使用它们调用 getAmountIn。

  • 对于在调用交换之前计算最佳代币数量很有用。

State-Changing Functions

addLiquidity

1
2
3
4
5
6
7
8
9
10
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);

向一个ERC-20⇄ERC-20交易池添加啊流动性

  • 为了覆盖所有可能的场景,msg.sender应该已经在tokenA/tokenB上为路由器提供了至少amountADesired/amountBDesired的配额
  • 始终根据交易执行时的价格,以理想的比例添加资产
  • 如果传递的代币池不存在,则会自动创建一个池,并准确添加amountADesired/amountBDesired 代币
Name Type
tokenA address 一个交易池中的 token
tokenB address 一个交易池中的 token
amountADesired uint 如果B/A价格<=amountBDesired/amountADesired(A贬值),则作为流动性添加 tokenA 数量
amountBDesired uint 如果A/B价格<=amountADesired/amountBDesired(B贬值),则作为流动性添加 tokenB 数量
amountAMin uint 限制交易恢复之前 B/A 价格可以上涨的程度。必须 <= amountADesired。
amountBMin uint 限制交易恢复之前 A/B 价格可以上涨的程度。必须 <= amountBDesired。
to address 流动性代币的接收者
deadline uint Unix 时间戳,在这之后将回滚
amountA uint 发送到池中的 tokenA 数量
amountB uint 发送到池中的 tokenB 数量
liquidity uint 铸造的流动性数量

addLiquidityETH

1
2
3
4
5
6
7
8
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns(uint amountToken, uint amountETH, uint liquidity)

向一个ERC-20⇄WETH交易池通过 ETH 添加流动性

  • 为了涵盖所有情况,msg.sender应该已经为路由器提供了至少 amountTokenDesired 的 token 余量
  • 始终根据交易执行时的价格,以理想的比例添加资产
  • msg.value被视为所需的 ETH 金额
  • 剩余的 ETH(如果有)将返回到 msg.sender
  • 如果传递的代币和 WETH 的池不存在,则会自动创建一个池,并添加正好amountTokenDesired/msg.value的代币
Name Type
token address 一个交易冲中的 token
amountTokenDesired uint 如果 WETH/token 价格<= amountTokenDesired/msg.value(WETH贬值),则作为流动性添加的 ETH 数量
msg.value
(amountETHDesired)
uint 如果代币/WETH 价格 <= amountTokenDesired/msg.value(WETH 贬值),则作为流动性添加的 ETH 数量。
amountTokenMin uint 限制 WETH/代币价格在交易回滚之前。必须 <= amountTokenDesired。
amountETHMin uint 限制 代币/WETH 价格在交易回滚之前。必须 <= msg.value。
to address 流动性代币的接收者
deadline uint Unix 时间戳,在此之后的交易回滚
amountToken uint 发送到池中的代币数量
amountETH uint 转换为 WETH 发送到池中的 ETH数量
liquidity uint 铸造的流动性代币数量

removeLiquidity

1
2
3
4
5
6
7
8
9
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);

移除一个 ERC-20⇄ERC-20 交易池的流动性

  • msg.sennder 应该已经为路由器提供了池中至少流动性的配额
Name Type
tokenA address 一个交易池 Token
tokenB address 一个交易池 Token
liquidity uint 要移除的流动性代币的数量
amountAMin uint 接收的 tokenA 的最小数量,无法满足时,交易回滚。
amountBMin uint 接收的 tokenB 的最小数量,无法满足时,交易回滚。
to address 基础资产的接收者
deadline uint Unix 时间戳,在这之后交易将发生回滚
amountA uint 收到的 tokenA 的数量
amountB uint 收到的 tokenB 的数量

removeLiquidityETH

1
2
3
4
5
6
7
8
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);

移除一个 ERC-20⇄WETH 交易池的流动性

  • msg.sennder 应该已经为路由器提供了池中至少流动性的配额
Name Type
token address 一个交易池 Token
liquidity uint 要移除的流动性代币数量
amountTokenMin uint 接收的 token 的最小数量,无法满足时,交易回滚。
amountETHMin uint 接收的 ETH 的最小数量,无法满足时,交易回滚。
to address 基础资产的接收者
deadline uint Unix 时间戳,在这之后交易将发生回滚
amountToken uint 收到的 token 的数量
amountETH uint 收到的 ETH 的数量

removeLiquidityWIthPermit

1
2
3
4
5
6
7
8
9
10
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8
)

得益于许可,无需预先批准即可从 ERC-20⇄ERC-20 池中移除流动性。

Name Type
tokenA address 一个交易池中的代币
tokenB address 一个交易池中的代币
liquidity uint 要移除的流动性代币的数量
amountAMin uint 接收的 tokenA 的最小数量,无法满足时,交易回滚。
amountBMin uint 接收的 tokenB 的最小数量,无法满足时,交易回滚。
to address 基础资产的接收者地址
deadline uint Unix 时间戳,在这之后交易将发生回滚
approveMax bool 签名中的批准金额是否用于流动性或 uint(-1)。
v uint8 许可签名的 v 部分
r bytes32 许可签名的 r 部分
s bytes32 许可签名的 s 部分
amountA uint 收到的 tokenA 数量。
amountB uint 收到的 tokenB 数量。

removeLiquidityETHWithPerimit

1
2
3
4
5
6
7
8
9
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8, bytes32 r, bytes32 s
) external returns (uint amountToken, uint AmountETH);

得益于许可,无需预先批准即可从 ERC-20⇄WETTH 池中移除流动性。

Name Type
token address 一个交易池中的代币
liquidity uint 要移除的流动性代币数量
amountTokenMin uint 接收的 token 的最小数量,无法满足时,交易回滚。
amountETHMin uint 接收的 ETH 的最小数量,无法满足时,交易回滚。
to address 基础资产的接收者地址
deadline uint Unix 时间戳,在这之后交易将发生回滚
approveMax bool 签名中的批准金额是否用于流动性或 uint(-1)。
v uint8 许可签名的 v 部分
r bytes32 许可签名的 r 部分
s bytes32 许可签名的 s 部分
amountToken uint 收到的 tokenA 数量。
amountETH uint 收到的 tokenb 数量。

removeLiquidityETHSupportingFeeOnTransferTokens

1
2
3
4
5
6
7
8
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);

removeLiquidityETH相同,但对于需要转账费用的代币会成功。

removeLiquidityETHWithPermitSupportingFeeOnTransferTokens

1
2
3
4
5
6
7
8
9
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);

removeLiquidityETHWithPermit相同,但对需要转账费用的代币会成功。

swapExactTokensForTokens

1
2
3
4
5
6
7
function swapExactTokensForToken(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);

沿着路径确定的路线,将准确数量的输入 Token 尽可能多的交换为我们要兑换的 Token。路径的第一个元素是输入的代币,最后一个是输出的代币任何中间元素表示要进行交易的中间对(如果不存在直接配对)。

  • msg.sender应该已经在输入令牌上为路由器提供了至少 amountIn 的余量。
Name Type
amountIn uint 要进行交换的输入代币的数量
amountOutMin uint 要兑换的代币的最小值,无法满足时,交易回滚。
path address[] calldata 一个代币对的地址数组。path.length必须>=2。没对连续地址的池必须存在且具有流动性。
to address 兑换完代币的接收者
deadline uint Unix 时间戳,在此之后交易将恢复。
amounts uint[] memory 输入 token 的数量和所有后续兑换出来的 token 的数量

swapTokensForExactTokens

1
2
3
4
5
6
7
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);

沿着路径确定的路线,以尽可能少的输入代币兑换准确数量的输出代币。路径的第一个元素是输入代币,最后一个元素是输出代币,任何中间元素表示要进行交易的中间代币(如果不存在直接配对)。

  • msg.sender 应该已经在输入Token 上为路由器提供了至少 amountInMax 的余量。
Name Type
amountOut uint 想要得到的兑换的代币的数量
amountInMax uint 最大输入的代币数量,如果不能满足,交易回滚。
path address[] calldata 代币地址的数组,path.length必须 >= 2。每对连续地址的池必须存在并具有流动性。
to address 兑换代币的接收者地址
deadline uint 时间戳,在此之后交易将恢复
amounts uint[] memory 输入代币金额和所有后续输出代币金额

swapExactETHForTokens

1
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts);

沿着路径确定的路线,将确切数量的 ETH 交换为尽可能多的输出代币。路径的第一个元素必须是 WETH,最后一个是输出代币,任何中间元素代表要进行交易的中间对(例如,如果不存在直接配对)。

Name Type
msg.value
(amountIn)
uint 发送的 ETH 的数量
amountOutMin uint 兑换出来的代币的最小数量,如果不能满足,交易回滚。
path address[] calldata 代币地址的数组,path.length必须 >= 2。每对连续地址的池必须存在并具有流动性。
to address 兑换代币的接收者地址
deadline uint Unix 时间戳,在此之后交易将回滚
amounts uint[] memory 输入代币金额和所有后续输出代币金额

swapTokensForExactETH

1
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts);

沿着路径确定的路线,以尽可能少的输入代币兑换准确数量的 ETH。路径的第一个元素是输入代币,最后一个元素必须是 WETH,任何中间元素代表要进行交易的中间对(例如,如果不存在直接对)。

  • msg.sender应该已经在输入 token 上为路由器提供了至少 amountInMax 的余量。
  • 如果to地址时智能合约,必须具有接收 ETH 的能力
Name Type
amountOut uint 接收的以太币的数量
amountInMax uint 最大花费的输入代币的数量,如果不能满足,交易回滚
path address[] calldata 代币地址的数组,path.length必须 >= 2。每对连续地址的池必须存在并具有流动性。
to address 兑换代币的接收者地址
deadline uint Unix 时间戳,在此之后交易将回滚
amounts uint[] memory 输入代币金额和所有后续输出代币金额

swapExactTokensForETH

1
function  swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts);

沿着路径确定的路线,将准确数量的代币兑换成尽可能多的 ETH。路径的第一个元素是输入代币,最后一个元素必须是 WETH,任何中间元素代表要进行交易的中间对(例如,如果不存在直接配对)。

  • 如果 to 地址是一个合约,那么这个合约必须具有接收 ETH 的能力
Name Type
amountIn uint 要发送的输入代币的数量
amountOutMin uint 最小的兑换出的 WETH 的数量,如果不能满足,交易回滚
path address[] calldata 代币地址的数组,path.length必须 >= 2。每对连续地址的池必须存在并具有流动性。
to address 兑换代币的接收者地址
deadline uint Unix 时间戳,在此之后交易将回滚
amounts uint[] memory 输入代币金额和所有后续输出代币金额

swapETHForExactTokens

1
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts);

沿着路径确定的路线,以尽可能少的 ETH 兑换准确数量的代币。路径的第一个元素必须是 WETH,最后一个是输出代币,任何中间元素代表要进行交易的中间对(例如,如果不存在直接配对)。

  • 剩余的 ETH(如果有)将返回给msg.sender
Name Type
amountOut uint 要兑换的输出代币的数量
msg.value
(amountInMax)
uint 最大花费的 ETH 的数量,如果不能满足,交易回滚
path address[] calldata 代币地址的数组,path.length必须 >= 2。每对连续地址的池必须存在并具有流动性。
to address 兑换代币的接收者地址
deadline uint Unix 时间戳,在此之后交易将回滚
amounts uint[] memory 输入代币金额和所有后续输出代币金额

swapExactTokensForTokensSupportingFeeOnTransferTokens

1
2
3
4
5
6
7
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;

与 swapExactTokensForTokens 相同,但对于转账时收取费用的代币会成功。

  • msg.sender 应该已经在输入令牌上为路由器提供了至少 amountIn 的余量。

swapExactETHForTokensSupportingFeeOnTransferTokens

1
2
3
4
5
6
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;

与 swapExactETHForTokens 相同,但对于需要转账费用的代币会成功。

swapExactTokensForETHSupportingFeeOnTransferTokens

1
2
3
4
5
6
7
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;

与 swapExactTokensForETH 相同,但对于需要转账费用的代币会成功。

  • 如果to地址是智能合约,它必须具有接收ETH的能力。

Interface

1
import '@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
pragma solidity >=0.6.2;

interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);

function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);

function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}

interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);

function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}