伴随着 ARB 的空投活动,Trader Joe 一跃成为 ARB Token Usage 榜上的第二大 DEX,并且超越了 Uniswap V3。是什么让 Trader Joe 拥有了超越 Uniswap V3 的能力?本文详细解释 Joe v2 AMM 算法 —— Liquidity Book.
由于 Arbitrum 近期空投活动的火热,随之产生巨量的 ARB 链上交易。Uniswap V3 早早布局 Arbitrum,自然是有先发优势。而 Trader Joe V2 的横空出世,伴随着 ARB 的热潮,一跃成为 ARB Token Usage 榜上的第二大 DEX。甚至在 3 月的最后一个星期,Joe V2 池一度占据了近 45% 的 ETH-ARB 币对的交易量,超越了 Uniswap V3 的池,成为了该币对交易量占有率最高的单池。而本文并不会花费大量篇幅讨论 Joe V2 为何能在 ARB 交易中获取大量份额,而是着重从 Joe V2 的 AMM 机制设计和技术实现入手,试图分析其产品的优势与不足。
我们都知道 Uniswap V3 构建的一套通过手续费收入和限价流动性博弈而提高资金利用效率的 AMM 机制。Joe V2 在此基础上进行了以下革新,引入了一种新的 AMM 模型 —— Liquidity Book:
垂直方向的流动性分布:Uniswap V3 的限价流动性本质上是水平方向上“平铺”在 LP 设定的价格区间内;而 Joe V2 则是在垂直方向上“堆叠” LP 提供的限价流动性。
"bin" 作为流动性分布的单元:如果说 Uniswap V3 中 "tick" 这一概念,可以形象地理解为流动性价格标尺上的“刻度”;那么 Joe V2 中的 "bin" 在这里可以理解成储存流动性的箱子。
类 ERC1155 的 LB Token:由于上面提到的流动性分布单元和方式,所以 Joe V2 基于 ERC1155 构建了一套流动性凭证体系 —— LB Token,同一个 bin 内的流动性是同质化的,而不同的 bin 中的流动性彼此区别。
流动性分布可策略化:正是因为 ERC1155 这种半同质化的 LB Token 属性加上垂直的流动性分布方向,使得 Joe V2 的 LP 可以按照一定的策略来部署自己的流动性,而不是简单地均分在 bin 上。
动态的手续费定价算法:swap 手续费动态定价,这使得 LP 在市场经历高波动性时可以收取更高的费用,在某种程度上通过手续费来博弈单边行情,从而对冲 LP 在高波动率行情下的无常损失。
接下来本文将进一步讨论上述这些特性的实现机制,以此帮助读者更好地理解 Joe V2 与其他 DEX 的异同。
我们知道自动做市商,AMM (Auto Market Maker) 中的流动性分布决定了特定价格下交易对两侧的相对数量,币对的相对数量又决定了池内当下的兑换比例,兑换比例即为大家所理解的“价格”。 Joe V2 中所设计的流动性账簿 (Liquidity Book) 将交易对的流动性安排成离散的 “bin”。而注入 bin 的流动性按照该 bin 定义的固定汇率(价格)进行兑换。换言之,单个 bin 内的流动性兑换遵循 $$x+y=k$$ 的恒定和 AMM 模型。
<div align="center">
<img src="https://img.learnblockchain.cn/attachments/2023/05/zhHA0WvM644fee949c26d.png" width="33%" height="33%">
</div>
如上图,单个 bin 内的流动性遵循 $$P⋅x+y=L$$的线性关系。$$x$$ 是该 bin 内 X 资产的数量,$$y$$ 是该 bin 内 Y 资产的数量,$$P$$ 是该 bin 对应的价格,$$L$$ 则为该 bin 内的流动性数量。 值得注意的是,上图中的“恒定和曲线”与 x 轴和 y 轴是有交点的,这意味着 X 或 Y 资产在一定交易量下是可以被消耗掉的。在这种情况下,当前价格会移动到下一个 bin(向左或向右)。
<div align="center">
<img src="https://img.learnblockchain.cn/attachments/2023/05/somkLjXe644feea1459e2.png" width="33%" height="33%">
</div>
某一交易对市场是其所有离散的流动性 bin 的聚合结果,一个市场内只能有一个同时包含 X 和 Y 的 bin - 在 Joe 中,被命名为 Active Bin (活跃价格区间),我们可以将其理解为该交易对当下的现货兑换比例。而所有在活跃区间右侧的区间都只包含 X 资产,所有在左侧的区间都只包含 Y 资产。 举一个简单例子,AVAX / USDC 池。资产 Y 为 USDC,资产 X 为 AVAX。价格 $$P$$ 由每个 AVAX 可兑换 USDC 的数量决定。如果此时 Active Bin 为 100 USDC per AVAX;所有在左侧的区间都只包含 USDC,而所有在右侧的区间都只包含 AVAX。如果市场内此时交易者大量购买 AVAX,那么当 100 USDC 内的 AVAX 储备被消耗完时, Active Bin 将向右移动。
也正是因为 LB 垂直聚合流动性这一特性,使得同质化流动性代币成为可能。我们姑且不说同质化流动性代币在 gas 上的种种优势,其对于协议中手续费计算和整个账务系统复杂度的轻量化也带来了更多可能性。
虽然说 LB Token 合约遵循 ERC-1155 多代币标准,而参量 id 即为该流动性所在的 bin 的索引 (index),所以同一 bin 所对应的 LB Token 是同质化的。从其合约代码中,我们可以发现:LB Token 的实现与 ERC1155 标准代币大致相似,主要区别在于它不会对接收方合约进行任何调用以防止重入攻击。同时由于其仅用于流动性计数,所以并未实现 URI 相关的函数。
如上面所提到的,Liquidity Book 聚合流动性的方式与 Uniswap V3 不同:在 Liquidity Book 中,通过每个 bin 垂直聚合流动性,在 Uniswap V3 中,流动性则是呈水平聚合。
<div align="center">
<img src="https://img.learnblockchain.cn/attachments/2023/05/YUY58JTp644feeac893a1.png" width="60%" height="60%">
</div>
Joe V2 内置的价格区间为 $$(2^{-128}, 2^{128})$$,这个价格区间被分割成一个个离散的价格点,每个价格点对应了一个流动性容器 $$Bin$$, 而决定分割精度的离散参数为 $$s$$ ,$$s$$ 越小,$$Bin$$ 就越多。
Joe V2 协议设定$$Bin$$的总数量为$$2*N_b$$,即价格为 1 以上的$$Bin$$和价格 1 以下的$$Bin$$各有$$N_b$$个,则有公式: $$ N_b=argmax_i((1+s)^i<2^{128}) $$ 除了价格的限制,协议还限制了 $$Bin$$ 的总数量不得超过 $$2^{24}$$ 个,也就是说 $$N_b$$ 最大为 $$2^{23}$$ 通过计算,我们可以得到 $$s$$ 的最小值为 $$2^{(0.5^{16})} - 1$$,从而我们可以得到 $$BinId$$ 范围为 $$[b-N_b,b+N_b]$$,其中 $$b = 2^{23}$$。 这里我们举个简单的例子演算一遍:
当 $$s = 0.0001$$ 时, $$ N_b=argmax_i((1+0.0001)^i<2^{128})=887272 $$
则 $$BinId$$ 为一组 $$(2^{23}-887272) ~ (2^{23}+887272)$$ 的连续正整数,即 $$BinId \in [7501336, 9275880]$$. $$Price$$ 与 $$BinId$$ 一一对应,符合以下的数学关系: $$ Price = 1.0001^{(BinId - 8388608)} $$
所以,$$Price$$ 的范围应该是: $$ 1.0001^{-887272}\eqslantless Price \eqslantless 1.0001^{887272} $$
显然,当 $$BinId = 8388608$$ 时, $$ Price = 1.0001^{(8388608-8388608)} = 1 $$
在库合约 TreeMath
中,为了优化流动性跟踪,$$Bin$$ 通过一个由三个 256 位数组嵌套创建的数据树来索引。在这棵树中,每个 $$Bin$$ 被分配了一个通过嵌套数组的位置路径。当一个 $$Bin$$ 内包含流动性,其对应的三个数组会被分配一个非零值。
<div align="center">
<img src="https://img.learnblockchain.cn/attachments/2023/05/gtBWJNiK644feece52f2e.png" width="60%" height="60%">
</div>
还是因为 Liquidity Book 垂直聚合流动性这一特性,LP 在提供流动性时,可以加入一些策略:Spot
/ Curve
/ Bid-Ask
,这是 Uniswap V3 这种水平聚合流动性的 AMM 模型所无法实现的,即便实现也需要进行多个仓位的流动性部署,对于 LP 用户来说操作成本和学习成本都过高。
以下是用户如何使用 Joe V2 的 Spot
策略分布的简单示例:
<div align="center">
<img src="https://img.learnblockchain.cn/attachments/2023/05/64HPJDqF644feedf85b1c.png" width="60%" height="60%">
</div>
在这个 ETH-USDC 池中,流动性提供者可以选择高于当前市场价格的范围,只向池中提供 ETH。随着 ETH 价格上涨,用户将稳步卖出 ETH 以换取 USDC。上图中的范围相对较小,但用户可以选择他们想要的任何目标价格——这是平均成本法 (DCA) 平仓策略的简单实现。
<div align="center">
<img src="https://img.learnblockchain.cn/attachments/2023/05/goKfuWJR644feee9cc957.png" width="60%" height="60%">
</div>
反之亦然;用户可以通过逆流程并以低于当前市场价格的单方供应 USDC 的方式,将 DCA 加仓策略用于 Liquidity Book 模型中。在这两种 Spot
策略应用中,用户通过单笔交易成本可控地逐渐退出或进入他们的头寸,并在此过程中赚取隔夜手续费收益。这些流动性策略为 LP 在部署流动性方面提供了极高的自由和灵活性。 bin 数越少,流动性越集中;因此,他们在该范围内交易中所占的收入份额就越大。
在所有 DEX 协议中,交易者在执行 swap 交易时向流动性提供者支付手续费,流动性提供者在获取手续费收益的同时,也承担着无常损失的风险。Liquidity Book 中引入了动态 swap 费用,使得 LP 在市场经历高波动性时可以收取更高的费用,在某种程度上通过更高的手续费来博弈单边行情,从而对冲 LP 在高波动率行情下的无常损失。
总 swap 费用将包含两个部分:基本费用 (Base fee)和动态费用 (Variable fee)。动态费用是瞬时价格波动的函数。费率将应用于每个 bin 中的 swap 金额,并按比例分配给该 bin 中的流动性提供者。
Swap 收取的费用由下列公式决定:
$$
f{s}=\sum{k=0}^{n}\left[(\operatorname{swap~amount}){k} *\left(f{b}+f{v}\right){k}\right]
$$
其中,$$f_b$$ 为 Base fee:
$$
f_b=B~ · s
$$
$$f_v$$ 为 Variable fee:
$$
f_v(k)=A(v_k·s)^2
$$
其数值取决于市场的波动性。市场的波动性是受交易频率影响的,当交易数额巨大以至于耗尽多个 bin 内的流动性(在价格大幅变动时)$$f_v$$ 会随之增长。
其中 $$v_k$$ 代表波动率累加器 volatility accumulator
是一种计算最近交易跨 bin 频率的参数。波动率累加器是市场波动率的参数化表现,该值将在每个计算步骤之间存储在合约内存 memory
中,其数值由两部分计算结果共同决定:
参考波动率(上一次波动率累加器的参考结果)和引入波动率(这一次交易引入的新波动率绝对值 $$(|i_r-activeId+k|)$$):
$$
v_a(k)=v_r + |i_r-activeId+k|
$$
参考波动率 (volatility reference, $$v_r$$) 取决于自上次交易以来经过的时间 $$t$$。我们定义了一个有上限和下限的时间过滤窗口。如果 t 小于过滤周期定义的下限(即定性为高频交易),则 $$v_r$$ 保持不变。如果 $$t$$ 大于衰减周期定义的上限(即定性为低频交易),则 $$v_r$$ 将重置为 0。如果 $$t$$ 在窗口内,则 $$v_r$$ 等于上一次的 $$v_a$$ 结果乘以衰减因子 $$R$$:
$$
v_r = \begin{cases}
v_r, & t < t_f \
R \cdot v_a, & t_f <= t < t_d \
0 , & t_d <= t
\end{cases}
$$
这意味着高频交易会增加波动率 $$v_a$$,而低频交易会慢慢降低波动率 $$v_a$$,以至于超过一定时间没有任何交易后将重置波动性 $$v_a$$
上面我们计算了参考波动率,接下来我们来计算引入波动率了。在引入波动率的计算中我们引入了另一个变量,即index reference
($$i_r$$)。在大多数情况下,$$i_r$$ 为该次交易前的 Active Bin
的 $$BinId$$。但在一定的时间窗口内(高频交易)时,$$i_r$$ 会保持原来的值。这是为了防止交易者通过进行小批量的小额交易来操纵手续费率:
$$
i_r = \begin{cases}
i_r, & t < t_f \
activeId, & t_f <= t
\end{cases}
$$
自 Uniswap V2 在其产品中实现了一套全价格区间分布流动性的方案以来,包括 Uniswap 自己在内,众多 DEX 项目都在寻求资金利用效率更优的 AMM 模型。即便是 Uniswap V3 上线届满 2 年的此刻,我们仍然无法断言什么是更好的 AMM 模型。但是忽略产品交互上的种种设计,单论核心业务层面的痛点,我们可以说理想的 DEX 应该符合如下特征:
虽然只是简单的几点需求,其中其实存在很多艰难地权衡:
首先,交易者的低交易成本和 LP 的高手续费收益本质上是冲突的,所以协议需要在一定的手续费率的前提下,将手续费更加合理的分配到 LP 的手中
而更合理的手续费分配机制本身就会增加系统的复杂度,这一点上又需要与 gas 经济性进行平衡
低滑点和可控的无常损失本质都依赖于更好的流动性深度,而在相同行情条件下,流动性深度与流动性分布机制乃至其资金利用效率息息相关。可是在资金规模确定的情况下,更高的资金利用效率必然会要更集中性的流动性分布算法,其带来的无常损失的风险也就越高。
我们看到 Joe V2,乃至刚刚上线的 V2.1 在可控的无常损失以及更好的资金利用效率两者之间的平衡中做出了创新;同样的,其在实现合理的手续费分配机制的基础上,也通过垂直流动性分布的方式进一步降低了系统复杂度,从而为降低用户操作的 gas 成本提供了空间。
Uniswap V3 的代码版权即将解禁的此刻,很多 DEX 项目踌躇满志地要跟着推出他们根据 V3 改进的新版本,而 Joe 则继续在一条更具有开创性的道路上不停地做出新的尝试,我们乐见其成,也期待更多更好的原创项目为交易市场带来新的活力。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!