Uniswap V2 第5章 移除流动性:按比例销毁 LP

讲解 Uniswap V2 如何销毁 LP token 按比例取回两种代币,burn 的数学,以及为什么移除流动性不收手续费。

4 分钟阅读
Uniswap V2 第5章 移除流动性:按比例销毁 LP

Uniswap V2 第 5 章:移除流动性(Remove Liquidity)

这一章是第 4 章的逆操作:销毁 LP token,按比例取回两种代币。Uniswap V2 的移除非常简单——纯粹按份额比例分两种币,不收任何手续费。我们讲清 burn 的数学和它和铸造的对称性。


目录


1. 移除流动性的本质

你持有一些 LP token,想退出。销毁(burn)这些 LP,池子按你占总 LP 的比例,把两种代币都还给你一部分。

核心思想:你拿回的每种币 = 你的 LP 占比 × 池子该币的储备。


2. burn 的核心公式

pair.burn 的核心(简化):

amount0 = liquidity · balance0 / totalSupply
amount1 = liquidity · balance1 / totalSupply
  • liquidity:你销毁的 LP 数量。
  • balance0/1:池子当前两种币的余额。
  • totalSupply:LP 总量。

然后销毁你的 LP、把 amount0/amount1 转给你、更新储备。注意它用的是合约实际余额 balance(而非缓存的 reserve),这样任何”直接转入但没记账”的代币也会被一并按比例分掉。


3. 案例:销毁 10% 的 LP

设池子 balance0 = 100 WETHbalance1 = 300,000 DAItotalSupply = 5,000 LP,你持有 500 LP(占 10%)。

amount_WETH = 500 · 100 / 5,000 = 10 WETH
amount_DAI  = 500 · 300,000 / 5,000 = 30,000 DAI

你拿回 10 WETH + 30,000 DAI(池子的 10%)。简单、对称、无手续费。


4. 为什么移除按比例、不收费

  • 按比例:你取出 10% 的 WETH 和 10% 的 DAI,池子取出后比例不变(k 等比例缩小),不影响价格。
  • 不收费:因为没有制造任何”隐含兑换”(你没把一种币换成另一种,只是等比例抽走)。这和第 2 章 swap 收费、以及 Curve 的失衡费逻辑一致——只有”改变池子比例”的操作才收费,等比例进出不收费。

对比:如果你想”退出时只要一种币”,Uniswap V2 没有内置的单币退出(不像 Curve)。你得先 burn 拿回两种币,再自己去 swap 一次(那一步才付 swap 手续费)。


5. removeLiquidity 的完整流程与滑点保护

通过 Router 的 removeLiquidity

function removeLiquidity(
    address tokenA, address tokenB, uint256 liquidity,
    uint256 amountAMin, uint256 amountBMin,
    address to, uint256 deadline
) external returns (uint256 amountA, uint256 amountB);

流程:

  1. 你先把 LP token approve 给 Router。
  2. Router 把你的 LP 转到 Pair,调用 pair.burn(to)
  3. Pair 按第 2 节公式算出 amountA/amountB,转给 to
  4. 滑点保护require(amountA >= amountAMin && amountB >= amountBMin)

amountAMin/amountBMin 防止你在交易被打包前价格/储备变动而取回过少。deadline 防止交易在内存池里搁置太久后才以陈旧价格执行。


6. 你取回的不一定是当初存入的组合

这是 LP 必须理解的一点:

  • 你当初存入 10 WETH + 30,000 DAI(当时 1 WETH=3000 DAI)。
  • 做 LP 期间,如果 ETH 涨价,套利者会从池子里买走 WETH、卖入 DAI,于是池子 WETH 变少、DAI 变多。
  • 你退出时按当前储备比例取回——可能变成 8 WETH + 35,000 DAI 之类。

这种”取回组合随价格变化而偏移”的现象,叠加上你本可以单纯持币的收益,差额就是著名的无常损失(impermanent loss)。手续费收入是用来补偿无常损失的。本课程不展开 IL 数学,但要建立这个直觉。


7. 本章小结

  1. 移除 = 销毁 LP,按占比取回两种币amount = liquidity·balance/totalSupply
  2. burn 用合约实际 balance 计算,等比例分配,不收手续费(没制造隐含兑换)。
  3. Uniswap V2 没有单币退出;要单一币种得先 burn 再自行 swap。
  4. Router 的 removeLiquidity 提供 amountAMin/amountBMin 滑点保护和 deadline
  5. 取回的组合按当前比例,可能偏离存入时的组合(无常损失的来源)。

8. 动手练习

对应课程的 Remove Liquidity 练习(和 Add 在同一个测试文件里)。

练习:removeLiquidity

主网分叉,先在 setUp 里 addLiquidity 拿到一些 LP,再移除。

interface IUniswapV2Router02 {
    function removeLiquidity(
        address tokenA, address tokenB, uint256 liquidity,
        uint256 amountAMin, uint256 amountBMin,
        address to, uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB);
}

思路:

  1. setUp / 测试开头:先 addLiquidity(DAI, WETH, ...) 拿到 liquidity,记下来。
  2. 把 LP token approve 给 Router:pair.approve(router, type(uint256).max)
  3. 调用 removeLiquidity(DAI, WETH, liquidity, 1, 1, user, block.timestamp)
  4. 打印返回的 amountA(DAI)、amountB(WETH)。
  5. 断言 pair.balanceOf(user) == 0(LP 烧光),且 user 的 DAI、WETH 余额都增加。

进阶

  • 验证按比例:移除前读 getReservestotalSupply,用第 2 节公式手算预期取回量,和实际返回对比。
  • 体会无常损失(选做):在 add 之后、remove 之前,用一笔大额 swap 把池子价格推动一下,再 remove,观察取回的两种币组合相对存入时发生了偏移。

运行

forge test --evm-version cancun --fork-url $FORK_URL \
  --match-path test/UniswapV2Liquidity.t.sol -vvv

下一章(第 6 章 Flash Swap)讲 Uniswap V2 的一个强大特性:先拿币、后付款的闪电兑换,以及它的手续费数学。

💬 评论