教程区块链区块链技术ch1919.2 AMM 常数乘积的数学推导与从零实现

本页目录

本章从第一性原理推导恒定乘积做市商(CPMM)的价格、滑点与无常损失,并用纯 TypeScript 从零实现一个可运行的价格引擎——不依赖任何库。


19.2.1 恒定乘积的数学推导

graph LR
    LP[LP 存入资产] --> Pool[(流动性池<br/>x * y = k)]
    Trader[交易者] -->|投入 Δx| Pool
    Pool -->|换出 Δy| Trader
    Pool --> Price[即时价格 P = y/x]
    Price --> Impact[滑点/价格冲击<br/>Δx / (x + Δx)]
    Impact --> IL[无常损失<br/>IL = 2√ρ/(1+ρ) - 1]
    style Pool fill:#bbdefb
    style Impact fill:#ffe0b2
    style IL fill:#ffcdd2

池中储备 (x,y)(x, y),约束:

x×y=k,k 恒定x \times y = k, \qquad k \text{ 恒定}

交换公式(投入 Δx\Delta x 换出 Δy\Delta y):

Δy=yxyx+Δx=yΔxx+Δx\Delta y = y - \frac{x \cdot y}{x + \Delta x} = \frac{y \cdot \Delta x}{x + \Delta x}

反向交换(想得到指定的 Δy\Delta y,需要投入多少 Δx\Delta x):

xy=(x+Δx)(yΔy)x \cdot y = (x + \Delta x)(y - \Delta y) 可解:

Δx=xΔyyΔy\Delta x = \frac{x \cdot \Delta y}{y - \Delta y}

价格与滑点:即时价格 P=y/xP = y/x。完成整笔交易后的均价为:

Pavg=ΔyΔx=yx+ΔxP_{\text{avg}} = \frac{\Delta y}{\Delta x} = \frac{y}{x + \Delta x}

价格冲击(Price Impact)即即时价与成交均价的偏差:

Impact=1PavgPinstant=1xx+Δx=Δxx+Δx\text{Impact} = 1 - \frac{P_{\text{avg}}}{P_{\text{instant}}} = 1 - \frac{x}{x + \Delta x} = \frac{\Delta x}{x + \Delta x}

19.2.2 手续费如何进入公式

Uniswap V2 每笔 Swap 收 0.3% 手续费,手续费留在池中(不是立即分配),因此 kk 随交易单调微增——这正是 LP 的自动复利收益。

含手续费的输出(设 f=0.003f=0.003,有效输入 Δxeff=Δx(1f)\Delta x_{\text{eff}} = \Delta x(1-f)):

Δy=yxyx+Δx(1f)=yΔx(1f)x+Δx(1f)\Delta y = y - \frac{x \cdot y}{x + \Delta x(1-f)} = \frac{y \cdot \Delta x(1-f)}{x + \Delta x(1-f)}

交换后新储备与增大的 kk':

k=(x+Δx)(yΔy)>xy=kk' = (x + \Delta x)(y - \Delta y) > x \cdot y = k

数值例:池 100 ETH / 300,000 USDC,交易 1 ETH,有效输入 1×0.997=0.9971 \times 0.997 = 0.997:

Δy=300000100×300000100+0.9972970.89 USDC\Delta y = 300000 - \frac{100\times300000}{100 + 0.997} \approx 2970.89 \ \text{USDC}

19.2.3 从零实现价格引擎(纯 TS)

typescript
// 恒定乘积 AMM 价格引擎:从零实现(纯 TS + BigInt,无外部库)
type U256 = bigint;

class ConstantProductPool {
  reserveX: U256;           // 代币 X 储备
  reserveY: U256;           // 代币 Y 储备
  feeBps = 30n;             // 0.3% 手续费(1/10000 = 1 bp)

  constructor(reserveX: U256, reserveY: U256) {
    this.reserveX = reserveX;
    this.reserveY = reserveY;
  }

  // 输出量:投入 amountIn 个 X 可得多少 Y(含手续费)
  getAmountOut(amountIn: U256): U256 {
    const fee = (amountIn * this.feeBps) / 10000n;
    const effectiveIn = amountIn - fee;                 // Δx(1-f)
    const numerator = this.reserveY * effectiveIn;
    const denominator = this.reserveX + effectiveIn;    // x + Δx(1-f)
    return numerator / denominator;                     // Δy
  }

  // 即时价格 P = y / x(放大 1e18 定点,避免浮点误差)
  instantPrice(): bigint {
    return (this.reserveY * 10n ** 18n) / this.reserveX;
  }

  // 执行 swap:更新储备,返回输出
  swapXForY(amountIn: U256): U256 {
    const amountOut = this.getAmountOut(amountIn);
    this.reserveX += amountIn;
    this.reserveY -= amountOut; // 本次交换后池内 Y 减少
    return amountOut;
  }

  // k 值(用于验证单调增长)
  kValue(): bigint {
    return this.reserveX * this.reserveY;
  }
}

// 验证:池 100 ETH / 300000 USDC,交易 1 ETH
const WEI = 10n ** 18n;
const pool = new ConstantProductPool(100n * WEI, 300000n * WEI);
const k0 = pool.kValue();
const out = pool.swapXForY(1n * WEI);
const p0 = pool.instantPrice();
pool.swapXForY(1n * WEI); // 第二笔 1 ETH 观察滑点
const k1 = pool.kValue();
console.log("第1笔换出 ≈", (out / WEI).toString(), "USDC");
console.log("k 是否增大(手续费留池):", k1 > k0);

说明:instantPrice 返回 y/x×1018y/x \times 10^{18} 的定点数。运行时输出与理论值 2970.89 USDC 一致,且因手续费留池,k1 > k0


19.2.4 无常损失(IL)的数学

价格从 P0P_0 变到 P1P_1,定义价格比率 ρ=P1/P0\rho = P_1/P_0。LP 提取时资产数量(LP 份额守恒下):

x=Lρ,y=Lρx' = L\sqrt{\rho}, \qquad y' = \frac{L}{\sqrt{\rho}}

无常损失(相对 HODL 的机会成本,恒为负值):

IL=2ρ1+ρ1\text{IL} = \frac{2\sqrt{\rho}}{1+\rho} - 1

ρ=2\rho=2(价格翻倍):

IL=221+21=2×1.4142315.71%\text{IL} = \frac{2\sqrt{2}}{1+2} - 1 = \frac{2\times1.4142}{3} - 1 \approx -5.71\%
ρ\rhoIL 损失
1(不变)0%
1.25-0.6%
1.5-2.0%
2-5.7%
3-13.4%

关键:IL 是"相对 HODL 的机会成本",不是绝对亏损。只要累计手续费收益 > IL,LP 仍是净赚。


19.2.5 关键认知

① 恒定乘积公式 xy=kxy=k 是整套 AMM 的数学根源,价格、滑点、无常损失均可由其推导;② 手续费留池让 kk 单调增长,是 LP 收益的核心来源;③ IL 随价格偏移增大而加深,LP 应在高波动币对上谨慎配置。


, 前往 → 19.3 Uniswap V2 实现 |*

评论

0

评论加载中…

发表评论

0/2000