Uniswap Part Ⅵ | 闪电贷

闪电贷

  • 第一种是普通的闪电贷,即借入 token 和还贷 token 相同,通过 UniswapV3Pool.flash() 完成
  • 第二种是类似 v2 的 flash swap,即借入 token 和还贷 token 不同,这个是通过 UniswapV3Pool.swap() 来完成的。

flash

普通闪电贷的接口为交易池合约的 UniswapV3Pool.flash() 函数

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
function flash(
address recipient, // 借贷方地址,用于调用回调函数
uint256 amount0, // 借贷的 token0 的数量
uint256 amount1, // 借贷的 token1 的数量
bytes calldata data //回调函数的参数
) external override lock noDelegateCall {
uint128 _liquidity = liquidity;
require(_liquidity > 0, 'L');

// 计算借贷所需要扣除的手续费
uint256 fee0 = FullMath.mulDivRoundingUp(amount0, fee, 1e6);
uint256 fee1 = FullMath.mulDivRoundingUp(amount1, fee, 1e6);
// 记录下当前的余额
uint256 balance0Before = balance0();
uint256 balance1Before = balance1();

// 将所需 token 发送给借贷方
if (amount0 > 0) TransferHelper.safeTransfer(token0, recipient, amount0);
if (amount1 > 0) TransferHelper.safeTransfer(token1, recipient, amount1);

// 调用借贷方地址的回调函数,将函数用户传入的 data 参数传给这个回调函数
IUniswapV3FlashCallback(msg.sender).uniswapV3FlashCallback(fee0, fee1, data);

// 记录调用完成后的余额
uint256 balance0After = balance0();
uint256 balance1After = balance1();

// 比对借出代币前和回调函数调用完成后余额的数量,对于每个 token,余额只能多不能少
require(balance0Before.add(fee0) <= balance0After, 'F0');
require(balance1Before.add(fee1) <= balance1After, 'F1');

// sub is safe because we know balanceAfter is gt balanceBefore by at least fee
// 手续费相关的计算
uint256 paid0 = balance0After - balance0Before;
uint256 paid1 = balance1After - balance1Before;

if (paid0 > 0) {
uint8 feeProtocol0 = slot0.feeProtocol % 16;
uint256 fees0 = feeProtocol0 == 0 ? 0 : paid0 / feeProtocol0;
if (uint128(fees0) > 0) protocolFees.token0 += uint128(fees0);
feeGrowthGlobal0X128 += FullMath.mulDiv(paid0 - fees0, FixedPoint128.Q128, _liquidity);
}
if (paid1 > 0) {
uint8 feeProtocol1 = slot0.feeProtocol >> 4;
uint256 fees1 = feeProtocol1 == 0 ? 0 : paid1 / feeProtocol1;
if (uint128(fees1) > 0) protocolFees.token1 += uint128(fees1);
feeGrowthGlobal1X128 += FullMath.mulDiv(paid1 - fees1, FixedPoint128.Q128, _liquidity);
}

emit Flash(msg.sender, recipient, amount0, amount1, paid0, paid1);
}

完整flash代码可以参考官方

flash swap

通过 UniswapV3Pool.swap() 函数,可以完成 flashswap 的功能

其中,在使用 flashswap 时,需要实现其 IUniswapV3SwapCallback 接口,完成闪电贷的还贷


Uniswap Part Ⅵ | 闪电贷
http://sissice.github.io/2022/09/29/uniswap-v3-6/
作者
Sissice
发布于
2022年9月29日
许可协议