本文解释了 Uniswap V3 是如何实现集中流动性的。我们假设读者已经了解了 Uniswap V2。
为了理解集中流动性,我们首先需要精确定义流动性,而这又取决于对储备的理解。
储备
代币的储备是指自动做市商 (AMM) 所持有的特定可交易代币的余额。我们使用 或简写为 来指代池子中持有的可交易代币 的数量,并使用 (有时简写为 )来指代池子中持有的可交易代币 的数量。
流动性
在 AMM 的语境下,流动性衡量的是代币对 和 的组合储备。
流动性提供者 (LPs) 在将代币存入池子以期在兑换期间赚取费用时,就是在提供流动性。他们的存款增加了储备,进而增加了流动性。
流动性是储备的函数。它通常是储备的乘积、乘积的平方或某些其他单调递增的储备函数(单调递增函数是指随着输入增加,输出总是增加的函数)。
在 Uniswap V2 中,流动性被衡量为 中的 (即储备的乘积)。
储备可以有不同的组合方式,但流动性保持不变。例如,如果有 1 ETH 和 1000 USDC,那么流动性就是 1000(1 ETH × 1000 USDC = 1000,忽略小数位)。
如果有 900 USDC 和 1.1111 ETH,流动性仍然是 1000,因为 900 × 1.1111 = 1000。
下面的动画绘制了 的图像,并连续改变 的值。请注意,随着 变大,曲线会离原点越来越远。
储备越多,曲线距离原点越远,流动性也就越大。
由于交易者支付的费用被吸收到了 Uniswap V2 的储备中,Uniswap V2 实际使用的不变量是 ,而不是 。为了保持数学计算的简单性,我们在本文中忽略了费用。
流动性与价格影响
高流动性是理想的,因为交易者可以“兑换出”更多的代币。如果一个池子只持有 1000 USDC,交易者不可能兑换出超过 1000 USDC。但即使他们不需要用尽某种特定代币的所有储备,交易者仍然偏好更高的流动性,因为更高的流动性会降低价格影响。
为了精确定义“价格影响”,我们首先需要精确定义 AMM 中的“价格”。
AMM 中资产的价格
Uniswap V2 中 token0 的价格是通过以下公式计算的:
在 Uniswap V3 中,代币 X 和 Y 也被称为 token0 和 token1。在这些章节中,我们将交替使用这两种表示法。
下面我们展示了一条常规的 价格曲线。曲线上的绿点代表当前 token0 和 token1 的储备量。回顾一下,我们使用 token0 和代币 X 指代同一事物(对于 token1 和代币 Y 也是如此)。随着绿点向左上方移动,token0 的价格随之上升,因为这对应于更少的 token0 储备:
正如上面的图形和公式中所示:
减少 token0 的储备会导致其价格上涨。这符合供需定律,因为 token0 越稀缺,它的价格就越高。
作为原点角度的价格
我们可以将“价格”可视化为一条从原点出发的射线(有起点但没有终点的线)。无论流动性如何,这条射线代表某种固定的储备比例。
思考一下,任何与下方黄色射线相交的储备组合都具有相同的比例。因此,这条射线与价格曲线的交点代表相同的价格,而与流动性大小无关:

设 为从原点到价格曲线上当前价格所在点的射线的角度。 的角度越大,价格越高:
既然我们对价格有了严格的定义和可视化,我们就可以定义和说明价格影响了。之后我们会将价格影响与流动性联系起来。
价格影响
AMM 中的任何交易都会导致价格向不利于交易者的方向移动。
如果交易者试图向池子提供 token1 来兑换出 token0,那么 token0 将会变得更贵。
正如前面所见,AMM 会根据池子中代币的供应量(储备)来调整价格。这确保了价格总是会随着买单或卖单发生变动。价格的上涨反映了需求的增加。
现在我们可以探讨价格如何随着一笔交易而发生变化。
小额订单的价格影响
假设你下了一个尽可能小的订单,通过向池子支付 token1 来买入一些 token0。这导致 token0 的储备略微下降,而 token1 的储备略微上升。因此,token0 的价格必然会上涨(上涨一小部分)。
换句话说,假设交易前的价格为
而交易后的价格为:
其中 是交易者支付给池子的 token1 数量, 是交易者从池子中获得的 token0 数量。
数量 和 及其对价格的影响在下图中进行了可视化展示:
无论 和 有多小(只要它们不为零),以下情况必然成立:
因此,AMM 上的任何交易,无论多小,都会改变价格。
我们将由交易引起的价格变动称为价格影响。
巨大的价格影响意味着价格发生了显著变动,而微小的价格影响则意味着价格仅发生了极小的变化。
不同流动性水平下的价格影响示例
对于固定规模的交易,流动性越大,价格影响越低。
本节展示了在流动性逐渐增加的池子中,进行相同交易(使用 USDT 购买 1 USDC)的三个示例。
示例 1:xy = 100
假设一个池子持有 10 USDC (token0) 和 10 USDT (token1)。因为 ,所以 。因此,流动性为 100。
如果交易者希望获得 1 USDC,他们必须使 USDC 的储备从 10 USDC 减少到 9 USDC。
然后他们必须投入足够的 USDT,使得 9 * new_reserve_usdt = 100(忽略费用)。求解出 new_reserve_usdt,我们得到 11.11。因为 USDT 的初始储备是 10,所以交易者必须投入 1.11 USDT 才能获得 1 USDC。如果我们看看交易后 USDC 的价格,我们会得到:
由于购买了 1 USDC,USDC 的价格从 1 USDT 变成了 1.234 USDT。
我们把初始价格 1 USDT : 1 USDC 称为起始价。
最终价是 1.234 USDT : 1 USDC。价格影响为 0.234,即比原价上涨了 23.4%。
我们在下面对这笔交易的价格影响进行了可视化展示。
价格起始于点状绿色射线和蓝色价格曲线的交点。绿色射线是按 绘制的,因为资产是以相同价格开始的。最终价格是红色射线与蓝色价格曲线相交的地方。在这里,价格影响非常明显(该图按比例绘制):

(我们假设两种代币具有相同数量的小数位,因此可以忽略小数位)。
示例 2:xy = 10,000
现在,假设该池子持有 100 USDC 和 100 USDT。因为 ,所以 。流动性比上一个示例增加了 10 倍。
如果交易者希望获得 1 USDC,他们必须将 USDC 的储备从 100 USDC 减少到 99 USDC。然后他们必须投入足够的 USDT,使得 99 * new_reserve_usdt = 10_000。求解出 new_reserve_usdt,我们得到 101.01。因为 USDT 的初始储备是 100,所以交易者必须投入 1.01 USDT 才能获得 1 USDC。如果我们看看交易后 USDC 的价格,我们会得到:
由于购买了 1 USDC(当储备起始为 100 USDC 和 100 USDT 时),USDC 的价格从 1 USDT 变成了 1.02 USDT,导致价格上涨了 2%。
在本示例和前一个示例中,交易者都获得了 1 USDC。然而,本示例中的价格影响要低得多(之前是 23 美分,而这里是 2 美分)。作为一个附带结果,交易者为这 1 USDC 支付的价格也更低,为 1.01 USDT,而第一个示例中是 1.11 USDT。
当 AMM 的流动性增加时,价格影响就会减少。
在这个例子中,价格影响明显更小:

示例 3:xy = 100亿亿 (1 quintillion)
为了把这点说透,假设储备分别为 10 亿 USDC 和 10 亿 USDT,而流动性为 100 亿亿 (1 quintillion)。
我们建议读者在阅读下面的计算过程之前,尝试自己解出价格影响。
如果交易者希望获得 1 USDC,他们必须将 USDC 储备从 10 亿 USDC 减少到 999,999,999 USDC。然后他们必须投入足够的 USDT,使得 999,999,999 * new_reserve_usdt = 1 quintillion (10 亿 10 亿)。求解 new_reserve_usdt,我们得到 1,000,000,001.000000001。因为 USDT 的初始储备是 10 亿,所以交易者必须投入 1.000000001 USDT 才能获得 1 USDC。如果我们看看交易后 USDC 的价格,我们会得到:
UDSC 以 USDT 计价的价格上涨了,但涨幅极小。
因此,当流动性相对于交易规模极其巨大时,价格影响几乎难以察觉。
资本高效的流动性
交易者倾向于较小的价格影响,但流动性提供者不希望为了实现这一目标而提供高达 20 亿美元的巨额资金。
我们希望在没有如此高资本需求的情况下实现高流动性。
我们希望我们的流动性是资本高效的。
为了使我们的流动性具备资本效率,我们利用了我们已知交易的“预期”价格这一事实。具体而言,由于 USDC 和 USDT 均与美元挂钩,因此它们被预期会以 1:1 的比例进行交易。
然而,由于价格影响,USDC 和 USDT 并不会总是以 1:1 进行交易——这正是我们试图最小化的问题。但我们希望在最小化价格影响的同时,提供远少于 20 亿美元的储备金。
因为我们预期交易价格为 1:1 或接近于 1:1,所以我们预计大部分交易会发生在储备金相互等同的区域,如下方的可视化图像所示。如果价格超出了这个区域,套利者将会买断更便宜的稳定币,并在交易所出售。因此,我们可以预期大多数交易会发生在下方的红色区域中:

闲置的流动性
正如上面曲线中所建模的,Uniswap V2 支持的交易价格范围基本上是从 0 到无穷大。将流动性分散到如此宽泛的价格范围内会浪费流动性,因为绝大部分流动性都不会被使用,尤其是在稳定币对的情况下。
更好的做法是消除在极端价格下允许交易的能力,以此换取在我们预期会发生交易的区域内获得更好的流动性。
集中流动性
如果我们能够从不期望发生交易的区域中“移除”流动性,并将这些流动性添加到预期区域中,结果会怎样呢?
以具体数字为例,假设我们希望我们的 AMM 在高于 0.99:1(99 美分的 Tether 兑换 1 个 USDC)以及低于 1.01:1(1.01 Tether 兑换 1 个 USDC)的价格区间内具有高流动性。回顾一下,随着我们在曲线上向左上方移动,价格是上升的。
如果我们在这些价格边界处添加一个 if 语句,我们可以让我们的 AMM 曲线看起来像下面的分段函数:
如果我们绘制上面的分段方程,我们会得到以下结果:
由于我们在预期稳定币交易的价格区间内拥有大得多的流动性,我们预计在该区域内的价格影响会显著降低。我们在不需要更多资金的情况下降低了绝大多数交易的价格影响。
当然,天下没有免费的午餐。如果价格偏离了 [0.99, 1.01] 的边界,流动性就会急剧下降。为了创建一个具有竞争力的池子,我们需要最优地设定边界。0.99 和 1.01 是不是最佳边界并不显而易见;将流动性乘除 10 倍是不是合适的比例也同样不是显而易见的。
Uniswap V3 是如何实现集中流动性的
为了在让 LP 决定存放流动性的理想边界和数量上保持灵活性,Uniswap V3 根本不使用比例因子。在特定的价格边界内, 将是 LP 在那里提供的流动性。也就是说,流动性提供者可以从多种价格区间中选择在哪里提供流动性。
我们在本文开头提到过,流动性与价格曲线到原点的距离成正比。
因此,由于不同价格区间的流动性不同,Uniswap V3 池子的价格曲线可能如下面的图形所示。
尽管这些曲线看起来是不连续的,但价格(用橙色射线表示)可以在每个“迷你 Uniswap V2 曲线”之间平滑过渡。每一个“子曲线”都具有 的形式,但每个子曲线的 值是不同的。某个子曲线的 值将完全取决于 LP 在该处投放了多少流动性。随着该片段的流动性 增加,其距离原点的距离也会增加。由于各曲线的流动性不同,它们距离原点的距离也会有所变化。
增加 意味着流动性提供者提供了正确的代币 和代币 的组合,从而将曲线向外推。在实际应用中,LP 指定一个流动性,然后 Uniswap V3 计算 LP 需要提供的 和 的数量。该片段所持有的 和 的数量会根据该区域发生的兑换而变化。目前我们不必担心每条子曲线的具体 和 数量,只需要知道它们的乘积是 。这将在后续章节中进一步讨论。
为了保持记账简单,LP 不能在任意价格边界提供流动性,而是只能在被称为 ticks 的预定义价格处提供。回想一下,价格与从原点到曲线上价格点的射线角度成正比。因此,我们可以将 ticks 可视化为价格曲线与从原点发出的预定义射线相交的地方:

如何选择这些 ticks 以及它们的间距将是后续章节的主题。
Uniswap V3 不变量
Uniswap V3 可以概念化为使用了以下不变量:
该不变量使得 LP 能够在不同的 ticks 之间提供不同的流动性。因此, 的值在曲线上的不同位置会有所变化。
下面的交互式工具展示了为不同片段改变 是如何改变该片段到原点的距离的。尽管这些曲线彼此并未“接触”,价格仍然可以在子曲线之间平滑移动(除非某个特定片段的 ,在这种情况下该片段将被跳过)。在实际操作中,这些片段比下面工具中展示的要小得多:
分段公式仅供说明
在实际情况中,像我们在上述公式中那样针对如此多潜在情况去检查价格并不节省 Gas。同样地,记录这么多的 值也是非常昂贵的。
因此,Uniswap V3 使用了一种替代机制来实现上述的分段公式,该机制极其复杂,几乎占了本书一半的篇幅。这个机制将在后面的章节中重新探讨。
然而,如果我们将 Uniswap V3 的曲线可视化,它看起来就像上面展示的曲线那样。
练习: 移动图像中的滑块,使所有的 值都相同。请注意,这将产生一条与 Uniswap V2 曲线完全相同的曲线,只不过这条曲线不会延伸到无穷大和 0。
流动性在实践中是如何分布的
不同片段的一些 值有可能是相同的。例如,可能会出现 的情况。如果没有在这个价格范围内放置任何流动性,那么某些 值也有可能为零。
每个 完全取决于 LP 选择在哪里添加流动性。
然而,LP 倾向于将流动性放置在他们预期会发生交易的区域附近,因为只有当 LP 的流动性实际被使用了,Uniswap V3 才会向他们发放兑换费用奖励(关于这是如何记账的,将在后续章节中讨论)。
在下面的屏幕录像中,我们看到了 Base 上的 ETH/USDC V3 池 的 Uniswap V3 LP 用户界面。灰色的垂直线是当前价格,而两条蓝线是 Uniswap V3 允许 LP 添加流动性的预定义的上下限价格。请注意,蓝线不能被设置在任意位置,只能设置在预定义的价格点上。
这是一张展示由两个稳定币组成的池子,其 Uniswap V3 曲线可能是什么样子的图表。

1:1 的价格(这是我们对稳定币对的预期)对应的是 45 度射线,此时储备比例等于 1。因此,流动性最终会集中在储备比例为 1:1 的中心区域周围:
下面是一张展示 Uniswap V3 如何可视化集中流动性的截图。在下方的 USDC / USDT 池中,我们可以看到在价格 1.000 附近存在着高流动性,而这里正是 LP 预期发生交易的地方:

(前往 以太坊主网上的 USDC/USDT 池 ,然后点击“添加流动性 (Add Liquidity) ”,就能看到上述图表)
对于 token0 比 token1 更昂贵的池子,流动性将倾向于更加集中在该价格周围:

如果市场价格发生了显著变化,那么流动性提供者将会移除他们的流动性,并将其放置在新的价格周围以捕获兑换费用。
跨越 ticks 不会造成中断
尽管曲线是不连续的,交易者仍然可以在不同的 ticks 之间无缝地进行交易。一旦跨越了一个 tick,Uniswap V3 就会为剩余的交易重新计算可用的流动性金额,如下面的动画所示:
当价格跨越该 tick 时,储备量突然跃升,因为此次兑换进入了一个流动性更高的区域,因此储备也更高。储备的这种跃升反映了 LP 之前投入该价格区间所增加的储备量。
结论
尽管 Uniswap V3 的代码库看起来可能令人生畏,但在高层次上,最终的机制是非常简单的。
Uniswap V3 拥有与 Uniswap V2 相同的基础机制:
- LP 可以添加和移除流动性,尽管在 V3 中,他们对于在哪里提供流动性有更多的选择。
- 兑换者(Swappers)可以将一种代币兑换成另一种代币。
- 两种协议都提供了用于追踪和检索历史价格的预言机(oracle)。
Uniswap V3 曲线就是一条流动性可能在预设价格(ticks)处发生变化的 Uniswap V2 曲线,这取决于 LP 是如何放置其流动性的。
这样的设计使得 LP 能够将他们的流动性集中在他们认为是该资产市场价格的附近。在流动性更高的情况下,交易者将获得更低的价格影响,从而使该池子成为交易者更具竞争力的选择。