06.Uniswap V2 闪电贷
目录
核心摘要 (Key Takeaways)
- Flash Swaps (闪电交换) 是一种无需任何抵押即可借出资产的机制,但前提是必须在同一笔区块链交易内归还借款本金及相应的手续费。
- 该机制的核心是原子性 (Atomicity),即整笔复杂操作(借款、执行自定义逻辑、还款)要么全部成功,要么全部失败回滚,从而保证资金池的安全。
- Flash Swaps 是 DeFi 可组合性 (Composability) 的强大体现,允许开发者像搭乐高一样,在单笔交易中调用多个协议(如 Uniswap, Compound, Aave)来执行复杂的套利或其它金融策略。
- 为了确保协议盈利,用户需要支付一笔手续费。这笔费用的最低标准是借出资产数量的
3/997,这个数值是通过数学计算确保资金池资产不会减少而得出的。 - 实现 Flash Swap 需要用户编写并部署一个智能合约,该合约必须实现一个特定的回调接口(
uniswapV2Call),Uniswap 的交易对(Pair)合约会通过调用这个接口来执行用户的自定义逻辑。
1. Flash Swaps 核心概念
Flash Swaps,也常被称为闪电贷 (Flash Loan),是 Uniswap V2 引入的一项创新功能。它与普通交易(Swap)的根本区别在于资金的获取和使用方式。
- 普通 Swap:用户必须先持有一种资产(如 ETH),才能将其兑换成池中的另一种资产(如 DAI)。
- Flash Swap:用户可以不持有任何资产,直接从流动性池中“借出”想要的资产,执行一系列操作,然后在同一笔交易结束前,将借出的资产和一笔手续费归还给池子。
1.1 为什么需要 Flash Swaps?
Flash Swaps 主要服务于需要大量临时资金的复杂链上操作,最典型的场景是套利。
- DeFi 产品的可组合性:DeFi 协议(如交易所、借贷平台、衍生品)都是开源且部署在链上的,可以像乐高积木一样被自由组合。Flash Swaps 提供了一个接口,让用户可以临时获得海量资金,去执行跨多个协议的复杂套利策略。
- 机会发现:当不同 DeFi 平台之间出现价差时,套利者可以利用 Flash Swaps 借入巨额资金来抹平价差并从中获利,而无需自己承担资金成本。
1.2 核心保障:原子性
Flash Swaps 的安全性依赖于区块链交易的原子性。
- 一笔交易内的所有操作(借款、调用其他合约、还款、验证)被捆绑在一起。
- 如果交易结束时,用户未能足额归还本金和手续费,整个交易就会被回滚 (Revert),就像什么都没有发生过一样。
- 这对资金池来说是零风险的,因为它要么成功收取了手续费,要么资产原封不动地保留在池中。
2. Flash Swap 的数学原理
为了保证流动性池在任何 Flash Swap 交易中都不会亏损,其背后有一套严谨的数学逻辑。
2.1 关键参数定义
-
普通 Swap:
- : 用户存入池子的资产数量 (Amount In)。
- : 用户从池子取出的资产数量 (Amount Out)。
- 手续费在
Amount In上收取,池子实际用于计算的是 。
-
Flash Swap:
- : 用户从池子借出的资产数量 (Amount Out)。
- : 用户最终还回池子的资产数量 (Amount In)。
- 核心关系:
2.2 手续费计算
Uniswap 的手续费总是对 Amount In(即存入池子的资金)收取的,费率为 0.3%。
- 在 Flash Swap 中,
Amount In是用户还回来的 。 - 因此,手续费 。
- 我们将此公式代入核心关系式中:
- 移项求解
Fee与 的关系: - 最后计算手续费:
- 最终得到手续费公式:
结论:用户需要归还的手续费,至少是你借出资产数量的
3/997。代码实现时通常会向上取整,以确保池子利益。
2.3 从资金池角度的验证逻辑
站在资金池的角度,必须确保在 Flash Swap 之后,池内对应资产的数量大于等于交易前的数量。
- 设池子原有某资产数量为 。
- 用户借走 ,池内剩余 。
- 用户还回 ,扣除 0.3% 手续费后,池子净增 。
- 交易后的总量为 。
- 为保证不亏损,必须满足以下不等式:
- 简化后得到: 这个不等式是 Pair 合约在交易结束时进行验证的核心,如果条件不满足,交易将失败。
3. Flash Swap 的实现流程
与普通用户通过前端或路由合约交互不同,Flash Swap 要求用户(通常是开发者)直接与 Pair 合约进行交互。
3.1 交互时序图 (Mermaid Sequence Diagram)
sequenceDiagram
actor User
participant UserContract as 用户合约
participant PairContract as Uniswap Pair 合约
User->>UserContract: 启动Flash Swap交易
UserContract->>PairContract: 1. 调用 swap(amountOut, to, data) 发起借款
PairContract->>UserContract: 2. transfer(token, amountOut) 发送借款
PairContract->>UserContract: 3. 回调 uniswapV2Call() 触发用户逻辑
activate UserContract
UserContract->>UserContract: 4. 执行自定义逻辑 (如跨协议套利)
UserContract->>PairContract: 5. transfer(token, amountOut + fee) 归还本金和手续费
deactivate UserContract
PairContract->>PairContract: 6. 内部验证还款是否足额 (balance >= initialBalance)
Note right of PairContract: 若验证失败, 整笔交易将回滚 (Revert)
sequenceDiagram
actor User
participant UserContract as 用户合约
participant PairContract as Uniswap Pair 合约
User->>UserContract: 启动Flash Swap交易
UserContract->>PairContract: 1. 调用 swap(amountOut, to, data) 发起借款
PairContract->>UserContract: 2. transfer(token, amountOut) 发送借款
PairContract->>UserContract: 3. 回调 uniswapV2Call() 触发用户逻辑
activate UserContract
UserContract->>UserContract: 4. 执行自定义逻辑 (如跨协议套利)
UserContract->>PairContract: 5. transfer(token, amountOut + fee) 归还本金和手续费
deactivate UserContract
PairContract->>PairContract: 6. 内部验证还款是否足额 (balance >= initialBalance)
Note right of PairContract: 若验证失败, 整笔交易将回滚 (Revert)
sequenceDiagram
actor User
participant UserContract as 用户合约
participant PairContract as Uniswap Pair 合约
User->>UserContract: 启动Flash Swap交易
UserContract->>PairContract: 1. 调用 swap(amountOut, to, data) 发起借款
PairContract->>UserContract: 2. transfer(token, amountOut) 发送借款
PairContract->>UserContract: 3. 回调 uniswapV2Call() 触发用户逻辑
activate UserContract
UserContract->>UserContract: 4. 执行自定义逻辑 (如跨协议套利)
UserContract->>PairContract: 5. transfer(token, amountOut + fee) 归还本金和手续费
deactivate UserContract
PairContract->>PairContract: 6. 内部验证还款是否足额 (balance >= initialBalance)
Note right of PairContract: 若验证失败, 整笔交易将回滚 (Revert)sequenceDiagram
actor User
participant UserContract as 用户合约
participant PairContract as Uniswap Pair 合约
User->>UserContract: 启动Flash Swap交易
UserContract->>PairContract: 1. 调用 swap(amountOut, to, data) 发起借款
PairContract->>UserContract: 2. transfer(token, amountOut) 发送借款
PairContract->>UserContract: 3. 回调 uniswapV2Call() 触发用户逻辑
activate UserContract
UserContract->>UserContract: 4. 执行自定义逻辑 (如跨协议套利)
UserContract->>PairContract: 5. transfer(token, amountOut + fee) 归还本金和手续费
deactivate UserContract
PairContract->>PairContract: 6. 内部验证还款是否足额 (balance >= initialBalance)
Note right of PairContract: 若验证失败, 整笔交易将回滚 (Revert)
3.2 流程解释
- 发起借款:用户的智能合约调用目标流动性池(Pair 合约)的
swap()方法。它会填充data参数,并指定amount0Out或amount1Out作为借出的 Token 数量。 - 发送资产:Pair 合约在收到请求后,首先会将用户请求的 Token 发送到用户合约地址。
- 执行回调:紧接着,Pair 合约会调用用户合约中实现的
uniswapV2Call方法。这是执行用户自定义逻辑的入口。 - 执行自定义逻辑:在
uniswapV2Call函数中,开发者可以编写任意复杂的逻辑,例如调用其他 DeFi 协议进行交易、抵押、借贷等。- 安全校验:在
uniswapV2Call函数内部,通常会进行安全检查,例如require(msg.sender == pair, 'Unauthorized'),确保该回调是由合法的 Pair 合约发起的。
- 安全校验:在
- 归还资金:在自定义逻辑执行完毕后,用户合约必须将借出的 Token 加上计算好的手续费转回给 Pair 合约。
- 手续费计算细节:如视频中代码示例所示,实际计算手续费时常用
(amount * 3 / 997) + 1的方式,+1是为了在整数除法中实现向上取整,确保支付的手续费只多不少。
- 手续费计算细节:如视频中代码示例所示,实际计算手续费时常用
- 最终验证:Pair 合约在回调执行完毕后,会检查池内资产余额。如果余额满足
期末余额 >= 期初余额的条件,则交易成功;否则,整笔交易被回滚。
4. Flash Swap 的实际应用与案例
Flash Swaps 最强大的用途是执行复杂的套利策略。
- 案例:bZx 协议套利事件
- 背景:一名套利者在没有自有资金的情况下,通过组合多个 DeFi 协议,在单笔交易中获利约 35 万美元。
- 操作步骤:
- 借款:通过
dYdX协议的闪电贷功能,借出 10,000 ETH。 - 抵押借贷:将其中 5,500 ETH 发送到
Compound协议,抵押借出 112 WBTC。 - 开空单:将另外 1,300 ETH 发送到
bZx协议,开设 5 倍杠杆的 ETH 空单。 - 价格操纵:将剩余的 5,637 ETH 在
Uniswap的 WBTC/ETH 池中大量卖出,导致 Uniswap 上的 WBTC 价格被瞬间拉高。 - 卖出获利:将在
Compound借到的 112 WBTC 在价格被拉高的Uniswap卖出,换回约 6,800 ETH。 - 归还贷款:将最初从
dYdX借来的 10,000 ETH 归还。
- 借款:通过
- 结果:通过这一系列复杂操作,套利者净赚了大量 ETH,而所有这一切都在一个区块内(一笔交易中)完成,充分展示了 DeFi 的可组合性和 Flash Swaps 的威力。