Uniswap V3上的流动性挖矿


Uniswap V3上的流动性挖矿

 

 

原文来源:https://www.paradigm.xyz/2021/05/liquidity-mining-on-uniswap-v3

作者:@danrobinson

 

Uniswap V3以非同质性的ERC721流动性仓位代替了同质性的ERC720流动性仓位。

这是否意味着V3不再支持灵活的V2式流动性挖矿了呢?或者说,这是否意味着V3上的流动性挖矿项目必须经由主动管理,才能奖励特定区间的流动性提供者?亦或是,是否只要提供大量不活跃的流动性便可以利用流动性挖矿项目了呢?

并非如此。

Uniswap V3 也支持 V2同款的流动性挖矿 — — 按比例激励所有活跃的流动性,每秒速率不变 — — 相比V2略小一些。这间接激励了流动性的不断集中,因为流动性提供者们所得到的奖励不由其提供的代币总价值决定,而是由自己实际所占的流动性份额(当其被判定为活跃时)决定的。这甚至在单币质押的合约中都是有效的,这意味着可以给予在同一时间质押相同流动性的人不同的奖励,也免去了为不同奖励部署新合约的麻烦。

Uniswap奖助计划(Uniswap Grants Program)资助了Omar Bohsali(目前是Paradigm的驻场企业家)以实现上述算法。我们也可以在 GitHub上跟进这个项目。

本文是我所写的学会打消顾虑并爱上非同质化流动性系列文章的第一篇。下一篇文章我们将讨论如何将Uniswap V3仓位用作抵押物。


 

价值数亿刀的算法

在了解一般的流动性挖矿算法是如何应用于Uniswap V3之前,我们首先需要明白流动性挖矿在Uniswap前几个版本中是如何运行的。

这种算法 — — 按比例分配奖励的有效增量计算 — — 在Bogdan Baton、Lucian Boca和Nick Johnson撰写的《以太坊区块链上的可拓展性奖励分配》一文中首次被提及。(感谢@FrankieIsLost发现了这篇宝藏文章)

SNX发起的针对Uniswap sETH池子的激励是第一个在链上计算奖励的流动性挖矿项目。这是在Unipool的sETH合约中实现的,由Anton Bukov于2019年编写完成。这是我心目中有史以来最具影响力的智能合约之一。

假设你希望在某个特定时间段对Uniswap V1或V2的流动性进行奖励。你决定按照时间、公平地给流动性提供者进行奖励的线性分配,比如,每秒以特定速率发放R个代币。

为了做到这一点,你可以想象一下将池子分割为单位为秒的时间切片。流动性提供者在每一个切片,都可以获得R·[ l(t)/L(t)]个代币,l(t) 代表的是每个流动性提供者在t时间段拥有的代币余额,L(T) 则代表在t时间段质押在该池子中的流动性总量。那么,他们从 t₀到 t₁的这段时间所获的奖励即是他们每秒所获奖励之和。

链外可以轻易搞定这类计算。但是我们如何在链上进行有效计算,做到只在有用户进入或离开池子时才进行增量更新?

假设,用户的余额l在这段时间内是固定不变的,那么我们就可以将上述公式简化为:

然后,我们就可以将这个总和拆解为两个和的差(Uniswap V2的Oracle累计器也采用了相似的做法)

这意味着我们只需要在质押合约中追踪单个累计器即可,这个累计器从池子开启之时就在追踪 “secondsPerLiquidity”

在Unipool的合约中,这个累计器被称为 rewardPerTokenStored。当任意质押或取出流动性的动作发生时 — — 会因此而改变 — — 质押合约便会更新sl累计器,在先前的总值中增加(tₙₒᴡ- tₗₐₛₜ)/L。(从技术上来讲,在Unipool合约及其大部分的分叉中,累计器会跟踪R/L,而并不会乘以之后的奖励率。)

当有人质押流动性时,合约会检验他们累计器的起始价值,s(t)。当有人撤出流动性时,合约会检查累计器更新的总值 s(t并计算出这段时间他们所获得的奖励:

Uniswap V1和V2并不需要为这些奖励提供什么内置支持,因为这些数字(包括累计器和校验过的总价)只有在与质押合约后交互后才会变化。

除去为追随流动性挖矿大势而打下基础的作用 — — 在这期间它被不断进行分叉 — — 这个天才算法已被证明具有通用性。例如,Uniswap V3便用了相似的算法来追踪单个仓位赚取的手续费(当然也增加了额外的技术以支持集中的流动性)。这一算法无疑在链上最为实用(效率即王道),不过它对简化链外的计算也很有帮助。UNI追溯分配的基础,便是一个在SQL中应用该算法的查询。

 

让我们回到Uniswap V3上

Uniswap V3的情况复杂了不少,不过也并非是无解的。

按照白皮书的描述,Uniswap V3引入了集中流动性的概念 — — 流动性只在当前价格tick(ic)保持在特定区间(ilower≤ ic iupper )内才算是活跃的。

这意味着,一次价格变动可以在不与质押合约交互的情况下,改变质押仓位的流动性余额。我们现在需要按照如下公示来计算一个具有流动性的仓位:

这也可以拆解为:

我们可以将这个公式理解为:

secondsPerLiquidityInside = seconds PerLiquidity — secondsPerLiquidity Below(lower Tick) — secondsPer LiquidityAbove(upper Tick).

第一个条款可以使用上文讨论过的全局sₗ累计器来计算。在Uniswap V3合约中,这个全局累计器,会作为secondsPerLiquidityX128, 与价格预言机一起被追踪。

为了计算其他两个条款,每当tick被越过时,Uniswap V3都会为每个tick去检验 secondsPerLiquidityOutside。“Outside”代表处于当前价格tick的对立位置。这让我们得以计算在任意时刻任意tick出现的整体 secondsPerLiquidity。举个例子,如果tickCurrent < i,那么 secondsPerLiquidityBelow(i) = secondsPerLiquidity — secondsPerLiquidityOutside(i);如果 tickCurrent >= i,那么 secondsPerLiquidityBelow(i) = secondsPerLiquidityOutside(i)。(这跟Uniswap V3跟踪计算高于或低于ticks时所赚取手续费的方式有相似之处。)

对任意区间而言,我们都可以用上述公示计算该区间的secondsPerLiquidityInside。Uniswap V3 做了计算,并通过便捷的 snapshotCumulativesInside 功能将结果展示了出来。

质押合约只需在用户质押时,快照 secondsPerLiquidityInside即可。当他们在之后撤走流动性,质押合约就会检查新的secondsPerLiquidityInside,记下差异,并将其乘以R·l,以计算出这段时间内该仓位赚取的全部奖励。


 

一些必要的折中方案

由于新系统的技术局限,我们采取了一些折中方案:

  • 模糊的结束时间:我们没有办法在奖励刚好结束的那一刻自动快照所有的累计器。在奖励结束后,合约有时无法区分流动性是在结束之前质押的还是结束后质押的。为了应对这种情况,合约可以对在奖励结束后撤出流动性的任意对象实行奖励率的衰减。想要锁定某一奖励率的用户便需要在奖励结束前撤走流动性。
  • 撤出的流动性:该算法会使用核心合约中活跃着的流动性总量,而这一总量可能会高于实际质押的流动性总量。撤出的流动性也会继续被分配一定的奖励份额,就好像是处于被质押而未被申领的状态。奖励的发起者可以指定一个申领期限,用户过了这一期限便能够收回所有未申领奖励。

 

结论

Uniswap V3并非流动性挖矿的“终结者”,相反,它为后者开启了一个巨大的设计空间。虽然本文解释了将“传统”流动性挖矿植入Uniswap V3的算法,但这也只是触及皮毛。正如白皮书第6.3节所说,V3的核心合约让几个指数(secondsOutside 和tickCumulativeOutside)始现面目。我也无比期待看到协议会如何利用这些新功能。

在接下来的文章中,我将探讨与Uniswap V3仓位相关的另一热点问题:借贷协议是如何将其作为抵押物使用的。

How do you rate this article?


1

0


Daily Universe Knowledge
Daily Universe Knowledge

🪐 We aim to help our users from all over the space know more about Universe Finance, Uniswap V3 and active liquidity management

Send a $0.01 microtip in crypto to the author, and earn yourself as you read!

20% to author / 80% to me.
We pay the tips from our rewards pool.