本文将解释如何确定自动做市商 (AMM) 中交易对的价格结算。它回答了这样一个问题:“从 AMM 中可以用多少代币 X 兑换代币 Y?”。
Uniswap V2 上的 swap() 函数要求你预先计算从池子中兑换的代币数量(包括 0.3% 的交易手续费)。
考虑一个 ETH / USDC 交易对,流动性池中有 100 ETH 和 100 USDC。为了简单起见,这里假设 1 ETH 价值 1 USDC。
虽然 1 ETH 的现货价格是 1 USDC,反之亦然,但这并不意味着我们可以用 25 USDC 兑换 25 ETH,因为这无法维持恒定乘积公式。
作者信息
本文由 RareSkills 的研究实习生 Aymeric Taylor(LinkedIn,Twitter)共同撰写。
恒定乘积公式理论:x * y ≥ k
恒定乘积公式规定,在代币 X 和代币 Y 的交易对池中,池内两种资产数量的乘积(X 乘以 Y)在任何时候都至少应保持恒定。
恒定乘积公式确保了两种代币之间的反比关系,从而对市场供需进行建模。当一种代币数量增加(存入 AMM)时,另一种代币数量应该减少(从 AMM 合约中提取)。
如果像下面的方程式那样重新排列变量,这种反比关系会表现得更加清晰。
让我们将前文提到的示例代入恒定乘积方程式中:
- x轴 = 100 ETH
- y轴 = 100 USDC
- k = 10,000 (100 ETH * 100 USDC)
- 粉红线 描绘了曲线 x * y ≥ 10,000

曲线下方的方框区域是常数 k,即 x 和 y 的乘积。
我们很快就会演示如何以保持该常数不变的方式将 ETH 兑换为 USDC。
Uniswap 恒定乘积公式实现
在实践中,恒定乘积公式的实现方式是比较交易前后流动性池的恒定乘积,以确保其至少保持不变。
Uniswap 并不阻止你向 AMM 支付多于你应付金额的代币,如果发生这种情况,那是因为你低估了可以提取的金额,责任在你自己,因此这里使用了 ≤ 符号。
将上述方程式展开,我们得到下面这个等价方程式:
x_Before和y_Before是兑换前池中每种代币的数量。x_After和y_After是兑换后池中代币的数量。
这意味着在将 ETH 兑换为 USDC 之后,池子的恒定乘积至少必须保持不变。
Uniswap V2 对每笔兑换收取 0.3% 的 AMM 交易费。当计入费用时,流动性池的恒定乘积会随着每笔兑换而增加。池子的这种增长是流动性提供者的核心激励。只有当流动性提供者提取其流动性时,池子的恒定乘积才会减少。我们将在本文末尾向你展示如何计算包含交易手续费的兑换。
为什么我们不能用 25 ETH 兑换 25 USDC
为了确定一笔兑换是否有效,我们需要预先计算该兑换将如何影响池子的恒定乘积。它至少能保持不变吗?
我们将用 ΔETH 和 ΔUSDC 分别表示换入和换出流动性池的数量。

用 25 ETH 兑换 25 USDC 意味着我们将 25 ETH 存入 AMM,并从中提取 25 USDC。这将把池子的流动性调整为 125 ETH 和 75 USDC。AMM 会拒绝这笔兑换,因为兑换后池子的恒定乘积会减小。

兑换后的乘积低于兑换前的乘积 10,000,这违反了恒定乘积不变式。下图将这笔兑换进行了可视化展示。

显然,我们不能指望提取 25 USDC —— 我们必须少提取一些,以保持恒定乘积不变式。
确定正确的 USDC 兑换数量
回到前面的示例,向池中添加 25 ETH 会将 ETH 的数量增加到 125 ETH(100 + 25)。接下来的任务是找到池中能够维持恒定乘积的新的且减少了的 USDC 数量,从而确保 AMM 会接受这笔兑换。

我们得到一个方程式,它揭示了可以用 25 ETH 兑换的 ΔUSDC 的最大值。
求解 ΔUSDC
我们重新排列该方程式以明确求解 ΔUSDC。


现在池子里有 125 ETH 和 80 USDC,这使得恒定乘积达到 10,000。

用 25 ETH 兑换 20 USDC 是你能够从 AMM 流动性池中提取的最大 USDC 数量。这笔兑换会被接受,因为它维持了恒定乘积公式。20 USDC 比 25 USDC 少了五分之一,因此我们在这次兑换中经历了滑点 (Slippage)。滑点是由于我们的交易导致价格变动的程度。如果我们进行较小规模的交易,最终支付的价格将接近 1 USDC : 1 ETH。但由于我们的交易量很大,最终我们要以更高的价格买到更少的 USDC,从而产生了更高的滑点。
我们可以在下方将这笔兑换可视化。

计算兑换的通用公式可以表示如下:

- x 和 y 代表兑换前流动性池中代币的数量
- Δx 代表存入 AMM 的代币数量
- Δy 代表从 AMM 换出的数量
算错兑换:向 AMM 支付超出应付的金额
如果你少提取一些,例如 18 USDC,AMM 仍然会接受它,因为流动性池中的恒定乘积增加了,但你会遭受损失,因为你没有实现兑换最大化。

计算包含手续费的兑换
我们上面进行的计算是排除交易手续费的“理论”计算。如前所述,Uniswap V2 对每笔兑换收取 0.3% 的交易费,但该费用仅适用于存入 AMM 的代币。假设我们用代币 X 兑换代币 Y,0.3% 的费用仅从 X 中扣除,而不从 Y 中扣除。
Uniswap V2 计算 0.3% 费用的方法是将存入的代币分为两部分:
- 手续费: 0.3%
- 剩余可用于兑换的金额: 99.7%
对于 25 ETH,我们的手续费和剩余可用于兑换的金额将是:
- 手续费 (0.3%):
0.075 ETH - 剩余可用于兑换的金额 (99.7%):
24.925 ETH
手续费会立即从该笔兑换的计算中剔除,因此兑换者将不会获得 0.3% 费用部分的计入。
剩下的是可用于兑换的金额,即 24.925 ETH。这是我们实际从池子中用于兑换 USDC 的金额。
让我们求解我们可以从池子中提取的 USDC 的最大数量 (ΔUSDC)。向池中添加 24.925 ETH 将把 ETH 数量增加到 124.925 ETH。

求解 ΔUSDC 我们得到:

考虑到 0.3% 的兑换手续费,我们大约可以从 AMM 中提取 19.952 USDC。这低于我们在无手续费示例中可以收到的 20 USDC。
在计入费用时,计算的主要区别在于我们将存入的代币乘以 99.7%,保留 0.3% 并分配给 AMM。假设 Δx 为存入的代币,Δy 为提取的代币数量,该通用方程式变为:

通过 RareSkills 了解更多
本文是我们高级 Solidity Bootcamp 的一部分。请查看课程大纲以了解更多信息。
原载于 2024 年 4 月 17 日