第四章:流动性提供——添加与移除算法及无常损失

大家好,我是你们的老朋友。今天我们来聊聊流动性提供这个核心话题。

说实话,在DeFi的世界里,流动性提供者(LP)才是真正的“幕后英雄”。没有他们,AMM就是空中楼阁。我自己刚入行时,第一次添加流动性就踩了坑——嗯,具体是什么坑,后面我会讲到。

一、添加流动性算法

添加流动性,说白了就是往资金池里存钱。但怎么存,存多少,这里头有讲究。

1.1 恒定乘积公式下的添加逻辑

在Uniswap V2风格的AMM中,核心公式是 x * y = k。当你添加流动性时,必须保持当前价格不变。也就是说,你存入的两种资产的比例,必须和当前池子里的比例一致。

举个例子:

  • 当前池子有100个ETH和200,000个USDC
  • 价格是1 ETH = 2,000 USDC
  • 你想添加流动性,存入10个ETH
  • 那么你必须同时存入20,000个USDC

为什么?因为如果比例不对,你存入后池子的价格就会偏移,这会产生套利空间,最终吃亏的还是你自己。

核心公式:

添加的资产数量应满足:Δx / Δy = x / y

其中x和y是当前池子里的储备量

1.2 代码实现要点

我习惯用Solidity来实现这个逻辑。这里给出一个简化版本:

function addLiquidity(uint256 amountX, uint256 amountY) external returns (uint256 liquidity) {
    // 获取当前储备量
    (uint256 reserveX, uint256 reserveY) = getReserves();
    
    // 计算应存入的Y数量
    uint256 optimalY = (amountX * reserveY) / reserveX;
    
    // 如果用户给的Y不够,就按实际给的Y反推X
    if (optimalY > amountY) {
        uint256 optimalX = (amountY * reserveX) / reserveY;
        // 使用optimalX和amountY
    }
    
    // 铸造LP代币
    liquidity = mintLPTokens(amountX, amountY);
}

这里有个细节:实际项目中,我们通常会让用户指定一个最大滑点,然后系统自动计算最优比例。我在做第一个AMM项目时,忘了处理这个边界情况,结果用户存了100个ETH但只存了1个USDC,池子直接崩了……

二、移除流动性算法

移除流动性就是添加的逆操作。你销毁LP代币,拿回对应的两种资产。

2.1 按比例赎回

你持有的LP代币占总供应量的比例,决定了你能赎回多少资产。公式很简单:

  • 赎回的X = (你的LP / 总LP) * 当前池子X总量
  • 赎回的Y = (你的LP / 总LP) * 当前池子Y总量

举个例子:

  • 总LP供应量是1000个
  • 你持有100个LP(占10%)
  • 当前池子有200个ETH和400,000个USDC
  • 你可以赎回20个ETH和40,000个USDC

小提示:移除流动性时,你拿回的是当前池子里的资产,不是你当初存入的那些。如果池子经历了大额交易,你拿回的比例可能和存入时完全不同。

2.2 代码实现

function removeLiquidity(uint256 liquidity) external returns (uint256 amountX, uint256 amountY) {
    // 获取当前储备量和总LP供应量
    (uint256 reserveX, uint256 reserveY) = getReserves();
    uint256 totalSupply = totalLPSupply();
    
    // 计算赎回数量
    amountX = (liquidity * reserveX) / totalSupply;
    amountY = (liquidity * reserveY) / totalSupply;
    
    // 销毁LP代币
    _burn(msg.sender, liquidity);
    
    // 转移资产
    transferTokens(msg.sender, amountX, amountY);
}

我曾经犯过一个低级错误:在计算赎回数量时,忘了更新储备量。结果用户赎回后,池子里的储备量没变,下一个用户就能多拿资产。嗯,那次审计被打了回来,记忆犹新。

三、无常损失概念与计算

这是流动性提供者最关心的问题,也是很多人亏钱的根源。

3.1 什么是无常损失?

无常损失,说白了就是:你提供流动性赚的手续费,还没资产价格波动带来的损失多。

为什么叫“无常”?因为如果你不撤出流动性,这个损失只是账面上的。一旦价格回到你存入时的水平,损失就消失了。但如果你在价格偏离时撤出,损失就变成了永久损失。

警告:无常损失不是“损失”,而是“相对损失”。它是相对于你单纯持有两种资产不动的收益差。

3.2 无常损失的计算公式

假设你存入时ETH价格是P0,当前ETH价格是P1。那么无常损失的公式是:

无常损失 = 2 * sqrt(r) / (1 + r) - 1

其中 r = P1 / P0(价格变化倍数)

这个公式怎么来的?我给大家拆解一下:

  1. 你存入时,池子里有x个ETH和y个USDC,满足x * y = k
  2. 价格变化后,池子里的ETH数量变为 x' = sqrt(k / P1)
  3. 你持有的LP份额对应的价值 = x' * P1 + y'
  4. 如果你单纯持有,价值 = x * P1 + y
  5. 两者相减,就是无常损失

3.3 实际数据演示

我们来看一个具体例子:

价格变化倍数 无常损失比例 举例说明
1.25x(上涨25%) 约0.6% ETH从2000涨到2500
2x(上涨100%) 约5.7% ETH从2000涨到4000
4x(上涨300%) 约20% ETH从2000涨到8000
0.5x(下跌50%) 约5.7% ETH从2000跌到1000
0.25x(下跌75%) 约20% ETH从2000跌到500

看到没?价格波动越大,无常损失越严重。而且涨和跌是对称的——涨100%和跌50%的无常损失是一样的。

关键结论:

  • 价格波动在25%以内,无常损失不到1%,基本可以忽略
  • 价格翻倍或腰斩,无常损失约5.7%
  • 价格涨4倍或跌75%,无常损失高达20%

3.4 如何对冲无常损失?

我个人的经验是,完全避免无常损失是不可能的,但可以降低影响:

  • 选择稳定币对:比如USDC/DAI,价格波动极小,无常损失几乎为零
  • 选择低波动资产:比如ETH/stETH,波动相对较小
  • 利用手续费覆盖:在交易量大的池子里,手续费收入可能超过无常损失
  • 使用单边流动性协议:比如Tokemak、Bancor V3,它们有保护机制

我曾经在2021年牛市时,把全部身家放进了ETH/USDC池子。结果ETH从2000涨到4000,我赚了手续费,但算上无常损失,收益还不如直接持有ETH。那次之后,我就学会了分散配置。

四、知识体系总览

下面这张图,是我自己总结的流动性提供核心逻辑:

流动性提供核心逻辑 添加流动性 移除流动性 无常损失 按比例存入两种资产 铸造LP代币 保持价格不变 销毁LP代币 按比例赎回资产 获取当前池子储备 价格波动导致相对损失 公式:2√r/(1+r)-1 波动越大损失越大 核心要点 添加/移除需按比例 → 无常损失不可避免 → 手续费可部分覆盖

这张图把三个核心模块串起来了。你想想看,添加和移除是操作层面的,无常损失是结果层面的。三者环环相扣,缺一不可。

我的建议:刚开始做LP时,先用小资金在稳定币对里练手。等熟悉了无常损失的计算和影响,再考虑进入波动性大的池子。记住,手续费收入是你的朋友,但无常损失是你的敌人。

好了,这一章的内容就到这里。流动性提供是个技术活,也是门艺术。希望你们在实际操作中,能避开我曾经踩过的坑。

专注资料整理