独家丨Paradigm研究合伙人:在Uniswap v3之上实现“经典”流动性挖矿
本文来源:https://www.paradigm.xyz/2021/05/liquidity-mining-on-uniswap-v3/
作者:Dan Robinson
Uniswap v3用非同质化的ERC-721流动性头寸代替了同质化的ERC-20流动性头寸。
这是否意味着它不再支持灵活的UniswapV2风格的流动性挖矿?必须选择特定的激励范围,积极管理流动性挖矿吗?还是可以通过提供大量非活跃流动性来在流动性挖矿中进行博弈?
不。
Uniswap v3可以支持与Uniswap v2相同类型的流动性挖矿——以每秒固定的速率、按比例激励所有活跃流动性,只需作出相对较小的折衷。它间接地激励了流动性的集中,因为流动性提供者根据他们在虚拟流动性中的份额(当它活跃时)获得奖励,而不是根据所提供代币的总价值。它甚至可以在一个单一的质押合约中做到这一切,使人们可以同时利用多种激励来质押相同的流动性,而无需为不同的激励措施部署新合约。
Omar Bohsali(现为Paradigm的驻场企业家)最近获得了Uniswap资助项目的资助,以实现该算法。您可以在GitHub上查看跟踪他的进度。
这是关于我如何学会停止担心并喜欢上非同质化流动性系列文章中的第一篇。下一篇文章将讨论Uniswap v3头寸将如何被用作抵押品。
价值十亿美元的算法
要了解标准流动性挖矿算法如何适用于Uniswap v3,我们首先需要了解它在早期版本的Uniswap中是如何工作的。
第一个在链上计算奖励的流动性挖矿项目是SNX对Uniswap sETH池的奖励。这是Anton Bukov在2019年撰写的Unipool sETH合约中实现的。我认为这是有史以来最具影响力的智能合约之一。
假设你想激励Uniswap v1或v2池在特定时期内的流动性。想要在流动性提供者之间公平地分配代币,并且是随时间线性分配(例如,以每秒R个代币的速度)。
请想象,以秒为单位将池子切成一片片。对于每个部分,给定的流动性提供者都应收到
个代币,其中l(t)是单个流动性提供者在t时刻的流动性代币余额,L(t)是该池在t时刻已质押的流动性总量。他们从t0到t1时间内得到的奖励将是这段时间内每秒奖励的总和:
这在链下是很容易计算的。但是我们如何才能在链上有效地计算它,在每次有人进入或退出池子时进行增量更新?
如果余额 l 在那段时间内是恒定的,则可以将以上公式简化为:
然后,我们可以将该和分解为两个和的差。(Uniswap v2中引入的oracle accumulator使用了非常类似的技巧。)
这意味着我们需要在质押合同中进行跟踪的是自池子开始时,就跟踪“每流动性秒数”这个指标的accumulator:
在Unipool合约中,这个accumulator 被称为 rewardPerTokenStored
。当任何人质押或解押流动性(即改变 L 时,质押合约会通过增加accumulator
到先前的值来更新Sl accumulator。(从技术上讲,在Unipool合同及其大部分的分叉中,accumulator跟踪
R/L,而不是在后面乘以奖励率。)
当某人质押流动性时,合约会检查其累计值的初始值Sl(t0)。当他们以后解押时,合约将查看accumulator的新值Sl(t1)并计算该期间的奖励:
Uniswap v1和v2不需要对这些激励措施的有任何内置支持,因为这些数字(accumulator和checkpointed values)仅在涉及质押合约时才会更改。
除了为收益农耕趋势奠定基础(在此过程中它被反复分叉),这种聪明的算法还具有相当多的用途。例如,Uniswap v3使用类似的算法来跟踪单个头寸赚取的费用(还有一些其他技巧来支持集中流动性)。它在链上是最有用的(效率很高),同时对简化链下计算也很有用。UNI追溯分配是基于一个查询,该查询在SQL中重新实现了该算法。
转入正题
Uniswap v3使情况复杂化,但并非无法解决。
如白皮书中所述,Uniswap v3支持集中流动性——流动性仅在当前的价格变动(ic)处于特定范围
内时才有效。
这意味着价格变动可以改变已抵押头寸的流动性余额,而不会涉及到抵押合同。对于具有 l 流动性的给定头寸,我们现在需要计算:
这可以分解为:
我们可以将其解释为secondsPerLiquidityInside = secondsPerLiquidity
– secondsPerLiquidityBelow(lowerTick) - secondsPerLiquidityAbove(upperTick)
。
可以使用上述相同的全局Sl accumulator来计算第一项。在Uniswap v3合约中,该全局accumulator与价格预言机一起被跟踪,如secondsPerLiquidityX128
。
为了让我们能够计算其他两个项,每经历一个时刻,Uniswap v3检查点secondsPerLiquidityOutside()
就会对该时点进行计算。“外部”是指与当前价格相对的价格变动。这让我们可以随时计算secondsPerLiquidity
任何一方的应计总额。例如,如果tickCurrent < i
,则secondsPerLiquidityBelow(i) = secondsPerLiquidity - secondsPerLiquidityOutside(i)
; 如果tickCurrent >= i
,则secondsPerLiquidityBelow(i) = secondsPerLiquidityOutside(i)
。(这与Uniswap v3跟踪和计算某时刻前后赚取的费用非常相似。)
因此,对于任意范围,我们都可以使用上面的公式来计算secondsPerLiquidityInside
该范围。Uniswap v3会为你执行此计算,并通过便捷snapshotCumulativesInside
函数公开结果。
当用户解押时,解押合约可以简单地对此secondsPerLiquidityInside
进行快照。当他们以后解押时,解押合约会查看新合约secondsPerLiquidityInside
,取其差额,并将其乘以 R·l ,以获得该时期内该头寸赚取的总奖励。
妥协
我们确实需要根据新系统的技术局限性作出一些妥协:
- 模糊的截止时间:无法在激励结束的确切时刻自动快照所有accumulators。截止后,合约不能完全区分截止前存入的流动性和之后存入的流动性。为了适应这一点,合约可以对激励结束后解押的人的奖励率进行衰减处理。想要锁定确切奖励率的人需要在此之前解押。
- ·非质押(Unstaked)的流动性:该算法使用核心合约中的活跃流动性总量,这可能高于总质押的流动性。非质押的流动性仍将被分配一部分奖励,就像它已被质押但未被领取一样。激励措施的创建者可以指定一个认领期限,在此期限之后他们可以收回所有无人认领的奖励。
结论
Uniswap v3并没“破坏”流动性挖矿,而是为其开辟了广阔的设计空间。尽管这篇文章描述了一种在Uniswap v3之上实现“经典”流动性挖矿的算法,但我认为谈得还是太浅了。如白皮书第6.3节所述,Uniswap v3核心合约公开了其他几个索引(例如secondsOutside和tickCumulativeOutside)。我期待看到协议是如何利用这些新功能的。
在以后的文章中,我将解决关于Uniswap v3头寸的另一个普遍关注的问题:贷款协议如何将其用作抵押品。