k特币如何交易 [科普]由浅入深理解UniswapV3白皮书

日期: 2024-09-06 16:02:53|浏览: 68|编号: 93507

友情提醒:信息内容由网友发布,请自鉴内容实用性。

k特币如何交易 [科普]由浅入深理解UniswapV3白皮书

y=k

相信大家已经很熟悉V1和V2版本的核心公式了。(不知道的可以看这篇文章——V1-Like模仿uniV1)。

虽然它是非常经典的AMM公式,但是它存在一个很大的问题,就是资金利用率低。

v2 价格范围

我们先简单回顾一下流动性池中资产的价格是如何表达的。

假设有资产X和Y,现在有一个由资产X和Y组成的交易对池,当我们想用资产X来给Y定价的时候,=x的数量/y的数量,这个很容易想到。

在直角坐标系中,我们用x轴表示资产X的数量,y轴表示资产Y的数量。那么,通过对上述公式进行变换,可以得到y = p * x。为了简单起见,我们用p来表示。

所以我们可以在坐标系中添加一条直线,它的斜率的倒数x/y就是价格p,当价格发生变化时,就是这条线的斜率发生变化。

流动性可以用矩形的面积来表示。因为k的实际含义是衡量一个池子里的流动性量,而x*y=k,即池子里的资产X量*资产Y量=流动性量。

img01:价格

上图中,资产Y的价格在下跌(X的价格在上涨),绿色区域的面积即为流动性数量k,需要保持不变。因此随着价格的变化,矩形的右上端点(图中红点)可以画出一条熟悉的双曲线。随着价格的下跌,红点逐渐上移,矩形的高度(y)不断增加,宽度(x)不断减小。当价格趋近于0的时候,红线会无限接近与y轴重合,但是不可能真的重合,因为绿色双曲线不会与坐标轴相交。因此我们池子做市的价格下限就是0,同理,价格的上限也是无限的(因为双曲线和x轴不会相交)。

所以当x*y=k时,做市的价格范围为(0,∞)。

资金利用率

价格范围 (0, ∞) 看起来很理想,我们的基金可以在任何时候(在任何价格点)为我们赚取佣金。

但我们忽略了影响收益的另外一个重要因素,就是资金的利用率,当一个用户使用我们的池子进行交易的时候,他的交易金额相对于我们的流动性来说是非常小的。

假设池中有 8 个资产 X 和 Y,价格 p 为 1。

现在有一笔订单,用1个X去兑换1个Y。我们先不考虑滑点和手续费的影响,这笔交易给我们带来的手续费收益为fee=1*0.3%,实际参与赚取手续费的流动性是1y的产出,相对于总流动性来说,这个数字是很小的。在这笔交易中,资金利用率大概是1/8。也就是说,我们只需要一小部分流动性来承载这笔交易,大部分流动性只是在交易过程中作为收益的分母躺在那里……

img02:评分

回到我们的坐标系,当用户将 X 兑换为 Y 时,价格会从低点上涨到高点。在红点移动到(X 的价格)的过程中,实际参与交易的流动性只有橙色矩形区域。为了方便查看,这里将价格变化范围夸大了。在实际交易过程中,价格变化不会这么大,因此橙色区域极小。

因此,提高利用率的关键是在保持函数模型不变的情况下,移除那些躺在那里什么也不做的流动性(绿色区域)。所以我们用虚拟流动性来代替它,也就是和,并且在添加流动性时,我们只需要注入橙色区域的流动性。所以公式就变成了这样:

$$ (x + x{})*(y + y{})=k $$

img03:真实

整个图形向左下方偏移。由于价格是直线的斜率,因此只要价格不超过指定范围,偏移对实际交易没有影响。

如上图所示,如果价格上涨超过,代表价格的点就会来到 y 轴的左边,也就是此时 x 的数量为负数。这是不可能的,因为现实中,资产数量为负数是没有意义的。所以当我们在池子里加入虚拟流动性的时候,我们注入进去的真正流动性只能在特定的价格区间做市。一旦价格超出范围,流动性耗尽,或者池子里某个资产的数量变成 0,它就不能再为市场提供流动性,除非价格再次回到范围。关于池子里所有资产从 X 到 Y 的转换,我们后面会讲到这个特性,这里我们回到资金利用率的问题。

如果你对线性代数不太擅长,可能会对翻译的方向感到困惑,所以这里用一个不太恰当的比喻来帮助大家理解虚拟流动性。回到图 02,你可以想象虚拟流动性就是真实流动性(橙色区域)在 x 轴和 y 轴方向的两个 pad,也就是绿色区域所补充的部分,帮助我们用更少的资金达到原有的做市效果。

事实上,对于使用交易功能的用户来说,v3模型和v2模型并没有什么区别,整个价格依然在xy=k曲线上运行((x + )整体看作x,y亦然)。无论V2还是V3,交易过程中真正用到的流动性只有橙色区域,更多的绿色区域则是虚拟的或者真实的流动性。对于他们来说并没有什么区别,他们观察到的依然是图02的模型。

提供流动性的用户看到的就是图03,在设定的价格区间内,我们解决了资金利用率的问题。

V3的核心公式 核心公式推导

V3的核心公式其实才刚刚出现,我们只需要计算虚拟流动性,为了方便后续计算,我们将代表流动性的k替换为^2,也就是L的平方。

现在我们回到图02,我们可以看到长度其实就是点的x,长度其实就是点的y。所以当上下限价格区间确定后,我们就可以分别用价格公式y=p*x和xy=L^2来换算虚拟流动性的长度。(这里为了统一变量名,价格点统一叫lower和upper,白皮书里是a和b,不影响结果。)

将前者代入后者,得到 p * x^2 = L^2,进而可以算出如何用 L 和平方根价格√p 来表示 x 和 y:

$$x = L / √p \y = L * √p$$

因此两种虚拟流动性可以写成:

$$x{} = L / √p{上} \y{} = L * √p{下}$$

核心公式即将浮现:

$$(x + L / √p{上}) (y + L √p{下}) = L^2$$

可以看到,公式中用到了和作为已知变量,所以在 V3 中要想增加流动性,需要用户设定做市的价格区间,在 V3 中,不同的创建者或者不同的价格区间(或者不同的手续费水平,后面会讲到)都是不同的流动性仓位。

在 V2 中,代表用户提供流动性的通证是 ERC20 类型的 LP 代币(token),因为所有流动性都可以看作是价格范围为 (0, ∞) 的流动性,因此可以用同质代币来流通。但在 V3 中,每种流动性可能有不同的价格范围,因此需要用非同质代币(NFT)来表示。

需要注意的是,当池子里的交易价格移动到做市价区间之外的时候,我们注入的流动性将不再赚取交易费,也就是处于非激活状态,当价格再次回到区间内的时候,流动性又会变得活跃起来。

流动资产变化

当价格变动时,流动性中的资产 Y 和资产 X 的数量都会发生变化。在 V2 中,这种变化会造成无常损失,而在 V3 中,其影响会被放大很多倍。因为当价格移动到范围之外时,你的流动性头寸实际上已经变成了单一资产,而另一种资产的数量已被重置为零。

图片04:

观察图中橙色区域的变化就很容易理解这一点,当价格持续上涨时,x 的值不断下降,直到达到价格上限,此时 x 被彻底清空。这一点和 V2 有很大不同,原因就在于 V3 引入了虚拟流动性。这也是为了提高资金利用率需要承担的风险。

价格区间的风险和收益

当价格在范围之外时,流动性头寸不仅无法继续赚取费用,而且会变成单一资产,而且一定是当时市场弱势的资产。例如,当资产Y价格上涨时,会有大量订单从池子里将资产X换成Y,因此池子里的X会越来越多,Y最终会被清算。因为AMM自动做市其实是一种被动做市,所以它始终需要成为市场上订单的交易对手。

也就是说,价格区间越窄,价格超出范围的概率越大,风险越大;价格区间越宽,风险越小。如果你讨厌价格超出范围的风险,可以直接将价格区间设置为(0,∞)。官方的UI界面也支持这个操作,那么你将获得全价格区间流动性,没有虚拟流动性,与V2类似。

当然这样做的代价就是资金利用率跟V2没什么区别,很低。这就相当于把资金均匀分布在一条很长的价格轴上,虽然每一笔交易都能赚到佣金,但是资金在每个价格点上被稀释太多,导致赚到的每一笔佣金权重很低。

添加和删​​除流动性

增加流动性的计算过程是了解其中一种输入资产的当前价格和数量,计算另一种资产的数量和增加的流动性的数量。

在V2中,加入了流动性,由于价格是两种资产的比值,所以很容易计算出另一种资产的数量,然后将两种资产的数量相乘,得到流动性的数量(xy=k)。但是V3引入了价格区间的概念,使得计算变得更加复杂。

让我们回顾一下计算虚拟流动性的过程,其中我们推导出如何使用 L 和平方根价格 √p 来表示 x 和 y:

$$x = L / √p \y = L * √p$$

价格 p 在区间内

img02:价格在范围内

< 页 <

假设添加的流动性如图02所示,当前价格包含在设定的价格范围内,橙色区域就是我们实际需要添加的流动性,虚拟流动性就是绿色区域的宽高减去橙色部分。

如果我们需要计算橙色部分,为了与上式中的 x 和 y 区分开来,我们把橙色部分的宽和高称为 delta x delta y。delta x 是 p(红点)与 x 轴的距离,delta y 是 p 与 y 轴的距离。所以我们可以这样写公式:

$$delta x = L / √p - L / √p{upper} = L * (√p{upper} - √p) / (√p √p_{upper}) \delta y = L √p - L √p_{lower} = L (√p - √p_{lower})$$

再次变换,将其重写为 L(流动性量)的方程

$$L = delta x (√p √p{upper}) / (√p{upper} - √p) \L = delta y / √(p - p_{lower})$$

x 和 delta y 是橙色区域的宽度和高度。这里我们已经知道其中一个,因为那是我们输入以注入流动性的资产之一的数量。上述两个公式中的任何一个都可以用来计算 L,因此无论给定 x 或 y 的数量,我们都可以得到要添加的流动性数量 L。得到 L 之后,我们可以根据另一个公式计算出另一种资产的数量。

价格 p 大于区间

img05:价格p大于区间

< 页

此时橙色区域已经消失,资产X的数量为0,所有流动性都变成了资产Y,其数量就是到y轴的距离,也就是图中的紫色虚线。我们根据delta y计算L:

$$L = delta y / √(p{upper} - p{lower})$$

价格 p 小于区间

img06:价格p小于区间

p <

此时橙色区域已经消失,资产Y的数量为0,所有流动性都变成了资产X,其数量就是到x轴的距离,也就是图中的蓝色虚线。我们根据delta x计算L:

$$L = delta x (√p_{upper} √p{lower}) / (√p{upper} - √p_{lower})$$

消除流动性

去除过程其实就是上述添加过程的逆操作,也分为三种情况,这里就不再详述了。

总结一下:V3的流动性计算流程,需要先确定价格区间,当前价格p,以及一种资产的数量delta x或者delta y,然后计算流动性数量L,以及另一种资产的数量。

限价订单

其实这种把资产X全部兑换成资产Y的特性,并不是缺陷,而是可以利用的特性。比如当我们跟市场持相反观点的时候,市场中​​大多数人看好X,而你看好Y(或者看淡X),所以你故意设置一个比较窄的价格区间(容易被价格突破),放在比现价高的地方。这时候注入的流动性就会是全部的资产X。当资产X价格上涨的时候,会先进入你的流动性价格区间,人们就会不断的用资产Y来换取你池子里的资产X,直到价格完全突破价格区间的上限,池子里的所有资产X都被资产Y所取代。其实这就是图04所示的过程。

图片04:

回顾整个流程,我们在一个价格区间内完成了从资产X到资产Y的转换,这是一种变相的限价单功能。与传统的限价单有两点区别:

贸易

在 V2 中,当用户在 UI 界面填写交易类型和一方(输入或输出)的准确金额时,UI 会自动根据公式 xy=k 计算出对方的预估金额和这笔交易的滑点。如果你查看 V2 的路由合约 Route 会发现,预估交易量的函数 quote 其实是一个纯函数,也就是只进行纯计算的函数。因为计算过程是根据池子里两种资产的总量和你的输入(或输出)进行比例换算的过程。

$$ = * / $$

观察上面V2的报价公式,你会发现计算数量只需要查询池中两种资产的总金额就可以进行转换,这两个数据是池合约对的属性,可以直接访问。

但在V3机制中,由于价格变化具有不确定性,因此无法通过本地计算来估算交易量。

图片07:

在上图中,左侧显示的是 V2 的流动性分布情况,可以看出在整个价格轴上是均匀分布的。中间显示的是 V3 的单个流动性仓位()的分布情况,也就是一个池子里只注入一种流动性时的状态,均匀分布在一个价格区间内。最右侧显示的是多次流动性注入叠加之后池子里的流动性分布情况,也就是由于每次注入流动性的价格区间不一样,所以会有重叠的区域,所以在重叠的区域,流动性会进行叠加,从而形成了右侧不同价格区间堆叠高度不同的柱状分布。

当然,上面的堆叠图只是示意图。实际的流动性分布将如下:

img08:ETH-UNI

现在假设价格处于持续上涨的趋势中,当价格从左到右开始跨越这些价格区间时,一种资产会不断被换成另一种资产,被换成的资产的储备量会不断减少。一旦当前价格区间的某种资产被耗尽,价格就会跨越当前区间,进入下一个区间,从而导致价格变动(因为价格向右移动,变大了)。在价格变动消耗池子里资产数量的过程中,投入的资产数量也会不断减少,一旦某个区间的投入资产被耗尽,价格就会停留在那个区间。

当然,单纯让价格在一个区间内是不准确的,这时候就需要我们利用加入流动性得出的公式,反向计算出一个准确的价格(在价格区间内)。

为了实现上述计算,需要知道每个 tick 上流动性的分布情况,然后像真实交易过程一样计算每个 tick 区间的流动性是否被逐一耗尽,最后得到成交价确认这笔交易的滑点水平。(UI 界面并没有这么做,而是用 . 来模拟调用合约的交易函数,最后读取信息里的预估数据,对此感兴趣的同学可以看分析部分,这里就不展开了)。

细心的同学可能已经发现,前面的描述中出现了一个新概念,叫tick,这就是我们接下来需要深入探讨的问题。

手续费

在 V2 中,因为大家都提供了统一的手续费标准(0.3%)和统一的价格区间(0,∞),所以大家的资金在整个价格轴上分布均匀,因此在每一笔交易中,大家的手续费加权计算比例也应该是相等的,也就是每笔手续费的收益分配只基于用户提供的流动性占总流动性的比例,谁贡献的多,谁的收益就多,这个很容易理解。

但V3的价格区间做市机制使得V2的分配机制不再公平,因为流动性有不同的做市区间,即不同的交易价格使用不同的流动性,此时再使用投资比例进行分配就不合适了。

正确的做法应该是,记录每一笔交易,使用了哪些流动性头寸,然后将这些头寸汇总起来,按比例分配。

这在理论上是合理的,如果是中心化网络,这样做的成本可能也是可以承受的。但在区块链的运行环境中,频繁且昂贵的读写操作是不可行的,而且会给用户带来极高的 Gas 费用,导致交易摩擦成本飙升,变得不经济。

我们需要一种高效利用天然气的实施方案。

离散价格点 刻度

优化的第一步,从价格轴入手。连续的价格轴可以有无限多的价格点,因为连区间(0,1)都可以划分成无限多的小数。如果在V3中我们还是使用连续的价格轴来记录,那将是一个无限扩展的变量。

那么我们确定了第一个条件,价格轴必须是不连续的,也就是离散的点的集合。成交价格只能局限在这些点上。

当然,限制价格点位也会导致价格不准确的问题,毕竟我们去掉了两个相邻点之间的价格。为了保证这个精度的误差不会对交易造成太大的影响,我们设置的点位间隔不能太大,所以我们就先设置为0.0001吧。

这样我们就得到了一个相差 0.0001 的等差数列。由于不支持小数,我们决定对这些等差元素进行编号,例如 0.0001 是数字 1,0.0002 是数字 2……

那么就不能再往下看了,因为最大的整数是 2^256,价格大概是 1,看上去上限已经够大了,但是我们忽略了另外一种情况,就是价格小于容差,也就是(0, 0.0001)之间的价格,很多小面值的代币如果跟 BTC、ETH 组成交易对的话,都在这个范围内,所以等差数列不是很合适。

事实上,虽然等比数列表现更好,但是问题本身仍然存在。

其实我们在设定等差数列或者等比数列的时候忽略了一个前提,当价格数值越大的时候,对价格精度的要求就越低(试想一下,当价格上万块钱的时候,价格波动会不会只限于0.0001的差值?),所以价格间隔没必要那么小。反之,当价格越小的时候,要求的价格精度就越高,要求的间隔就越小。所以我们需要的是一个间隔从极小逐渐增大的序列。

这是 V3 使用的幂等序列。即:

$$p_{i}=1.0001^i$$

这里的i是价格序号,一个int24类型(有符号),当i为0时,价格为1,是价格的基点,i越大,区间越大,i越小,区间越小,i为负数时,其实就是1.0001的平方根,价格是区间(0,1)内的一个值。

由于实际计算过程中采用的是价格的平方根√p,而非价格p(例如前面流动性与代币数量的换算),所以我们需要将价格表达式调整为:

$$√p_{i}=(√1.0001)^i$$

V3中的价格范围是(√1.0001)^(int24).min到(√1.0001)^(int24).max,这个价格区间足够宽,满足交易中的准确性要求。

这里的i是价格的序号,我们称之为tick,所有序号的集合我们称之为Ticks。在合约代码中,ticks主要用来记录流动性的间隔。

交易费用水平和

我们利用幂等序列将连续的价格轴转化为离散的点集,这在简化上迈出了一大步,但不幸的是这还不够。因为市场上交易对的价格波动并不均匀,例如由两种稳定币(dai+usdc)组成的交易对的波动集中在很小的范围内,而如果是两种(山寨币),价格波动可能就很大。对于波动较小的交易对,需要更密集的价格点来提高准确率,而波动非常大的交易对不需要在密集的价格点计算中消耗太多的gas,即价格点分布比较稀疏。

不仅价格点的密度要求不同,不同波动率的交易对需要收取的费用水平也不同。例如,对于稳定币交易对,由于波动率很小,交易产生的价差不太可能太大。如果收取 0.3% 或更高的费用,则不合适,不利于市场流动性。对于两个山寨币的交易对,由于波动率很大,产生的价差也可能很大。即使收取 1% 的费用,也有很多人愿意执行交易。

因此V3引入了三种可选的费率档位和对应的tick密度,即每个交易对都有0.05%、0.3%、1%三个可选费率档位,未来通过社区治理可以永久增加可选档位。每个交易费率档位都是给定的,比如一个稳定币交易对,意味着每个tick之间必须有10个tick的间隔才有效可以使用,间隔内的tick虽然存在,但是程序并不会初始化使用它们,也不会产生任何gas费用。因此我们在幂等序列的基础上进一步节省了计算消耗。

V3设置速率级别:

费率建议的使用范围

0.05%

10

稳定币交易对

0.3%

60

适用于大多数交易对

1%

200

高度波动的交易对

tick上的数据是描述一个交易池状态的基础数据,每一笔交易对价格、流动性、手续费的影响都要在tick数据上进行操作。

为了准确计算出每一个流动性头寸应得的佣金收入,或者其在总收入中所占的权重,需要准确记录每一个价格点上可用的流动性数量,以及每一个价格点上收取的佣金。

这两个是与tick上存储的流动性相关的数据。

:很好理解,每当有流动性将tick设置为价格范围时,价格的上限和下限都会增加。也就是说,当>0时,表示tick已经初始化,正在被流动性使用,而==0则表示tick尚未初始化,没有流动性使用,在计算中可以忽略。

:表示当价格穿过该刻度时,流动性需要改变的金额才能激活。

当注入或移除流动性数量l时,具体规则如下:

初次看到这个规则,你可能会感到疑惑,为什么注入流动性时会减少,而撤出流动性时却会增加呢?其实,你需要把这个变量理解为delta L。

在流动性章节中,我们说过,流动性有两种状态:激活和非激活。也就是说,包含当前价格的价格范围处于激活状态,反之亦然。那么在一个池子里,激活状态的流动性数量总是随着价格的变化而变化的。记录的是价格经过tick时需要增加或减少的金额。

举个例子:假设有两个首尾相连的价格区间(a,b)和(b,c),流动性分别为1和2。当价格从a点左边进入(a,b)区间时,池子的激活流动性应该增加1,因此在a的tick上写上+=1。当价格到达b点时,已经离开了(a,b)区间,池子的激活流动性应该减少1,因此在b点的tick上写上-=1。接着进入第二个区间,刚刚减少的池子里的激活流动性又要增加,因此在b的tick上再次写上+=2,直到价格经过c点,池子里的激活流动性又需要减少2,在c点的tick上写上-=2。

我们需要的是一个可以精确控制池子里激活流动性总量的差值,这也是为什么会有增加和减少的原因。其实在UI界面上画一个精准的流动性分布图,像图08,就是用当前池子里激活流动性的总量,在每一笔tick上加减的结果。

现在我们知道了tick上的流动性分布,那么我们可以计算一下交易费的收入吗?

直接累计收费方案

现在我们来设计一个费用计算方案,由于我们已经得到了流动性的分布,所以我们可以根据对应的交易量和对应的流动性头寸,加上每笔交易产生的费用。

这个过程很直观,逻辑也不复杂,但是消耗的gas比较多。

更别说一笔交易可能跨越很多个 tick,单单一个 tick 的计算就可能涉及大量的流动性仓位,这不仅需要一个耗时的遍历和搜索过程,更严重的问题是,每个流动性仓位要收取的交易费都必须是一个变量,当我们逐个写入新值时,gas 费就会飙升。

上述方案让交易者承担做市商的 Gas 费,因为记录手续费分配明细是做市商的业务。对于交易者来说,承担了手续费之后还要花很多 Gas 去帮交易对手记录如何分钱,这绝对不是什么愉快的体验,事实上就连做市商也不愿意承担。

高昂的 Gas 费是这个方案最大的阻碍,采用遍历的原因是分配方案需要保证公平性:

如果我们想避免昂贵的遍历操作,同时保证上述两个公平性,我们需要改变我们的方法。

我们不妨将任务分成几个部分来实现它。

相同间隔之间的分配

为了简化问题,我们假设该池中的所有流动性价格范围都是(0,∞)。

之所以要在交易时遍历流动性规模比例(贡献比例),是因为池子里所有流动性仓位的数量和规模比例会不断变化,你不可能缓存一个固定的比例,然后在每次交易中都按照这个固定的比例进行分配。

由于流动性头寸可能随时被移除或注入,因此该比率不能保证始终正确,需要针对每笔交易进行计算。

因此,我们应该放弃计算流动性的比例,而是计算每单位流动性可以获得的费用金额(即1个流动性产生的费用收入)。

当提供流动性的用户撤回费用时,我们可以获得他提供的流动性,我们只需要将其额度乘以每单位的费用收入即可获得他应得的费用。

$$费用= delta l *(fee {} / {})$$

我们设定了一个值,以记录全球每单位流动性所赚取的交易费用的累积价值(请注意,这是一个累积价值)。

有2个相关的全球变量:

在交易期间,有一个相关的本地变量:

我们只需要将其除以三角洲费用即可每次需要增加的金额。

$$ += delta费用 / $$

对于任何相同的价格范围(由不同的用户注入),您只需要在此期间计算流动性变化(注入或拆除)的增量,然后将其乘以流动性的数量即可知道在此期间内收取的处理费的增量,以最终将其添加到耗油的费用。

让我们整理出来:

不同间隔之间的分配

我们刚刚在相同的间隔内解决了分配方案,或者统一的时间间隔(0,∞)。

我们如何以公平和高效的方式分配不同的间隔?

回顾交易过程,每次价格转移到某个刻度时,它都会不断消耗其流动性,这是处理费的根本原因,因此,如果我们记录了tick上的每个费用,则用户收集处理费,然后在间隔内总结所有tick数据。

听起来不错,但是仍然存在问题,因为价格范围可能有很多滴答,这使我们回到了遍历遍历的问题。

我们需要打破我们的注意力的局限性,并将目光移至价格范围之外。

如果我们知道收取费用的范围之外的费用,我们可以间接了解该范围内的费用吗?

feeGrowthInside = feeGrowthGlobal - feeGrowthOutside

如果交易在价格范围内进行(a,b),则处理费将在范围内保持不变,但是在范围内保持不变,即在范围内的处理费(0,a)和(b,∞)并没有增加范围(a,b)的范围。

$$ = - {下} - {上面} $$

OW对应于间隔(0,a),而VE对应于间隔(B,∞)。

当用作流动性边界时,我们需要在刻度上添加一个新变量,以记录间隔以外的总费用。

如果将刻度用作中央轴,则价格是内部的,而另一侧是外部。

此外,如果没有流动性将tick用作边界时,我们就不需要考虑此变量,因此,在注入流动性时,我们将tick初始化放在tick初始化,初始化与价格边界相对应的两个刻度以及一定刻度上的流动性返回到零(== 0)时,我们可以在计算中再次忽略它。

整理一下

假设价格是在Ith tick中的

每当注入流动性时,与价格边界相对应的刻度具有以下初始化规则:

在交易期间,有以下更新规则:

在刻度上的变量后,可以获得间隔两侧的外部费用。

$$ = -OW -VE $$

需要根据点A和B之间的位置关系来确定下和更高的计算。

假设我们需要计算A和B点之间的交易费,而当前点是B点B的右侧。

........

...

...

目前在B点的右侧,实际记录的是B点左侧的处理费,上面我们需要计算的应该是B点右侧的处理费,因此我们实际上需要使用减法。

feeGrowthOutside_below = feeGrowthOutside_a // a点所对应的tick的feeGrowthOutside
feeGrowthOutside_above = feeGrowthGlobal - feeGrowthOutside_b // b点所对应的tick的feeGrowthOutside

代替先前的公式

feeGrowthInside = feeGrowthGlobal - feeGrowthOutside_a - (feeGrowthGlobal - feeGrowthOutside_b)

请注意,根据A和B之间的不同位置关系,必须确定上述和下方的计算方法。

2022.03.23纠正了VE的计算并补充了判决逻辑。

V3费用的完整过程

现在,我们连接两个解决方案,即V3解决方案。

首先,我们需要记录池中每单位移动性数量的累积变量,以收取处理费用的费用。

$ $ = - {lower} - {upper} $ $

当流动性变化,从上次到当前时间增加的处理费用时,将在此间隔中注入不同的流动性位置。

用户收取处理费,并从其他变量中扣除。

实际上有两种类型的V3,一种是池合同(属于基础合同,通常不会直接与用户互动)

V2的处理费计算过程是在交易和删除流动性过程中隐藏的,逻辑相对简单。

甲骨文

V2的预言机提供了TWAP(时间加权的平均价格)是每个块的第一个交易的价格。

$$ at = a {t-1} +价格 * delta time $$

外部用户可以通过记录价值的变化和时间点来获得加权价格,以减少一段时间内短期波动的影响。

$$ p(t1,t2)=(a {t2} - a {t1}) /(t2 -t1)$$

上述公式是从T1到T2的时间的时间获得的,因为其值是在时间之后加权的(累计价格乘以时间),因此它受到短期波动的影响较小,这可以有效防止恶意价格波动。

V2预言机仅保留核心合同的最新价值,因此,如果外部用户想使用此先知,则需要自己构建一组监视和记录设施,从而增加用户成本。

与V2的预测机相比,V3具有以下重大变化:

与v2相比,价格是价格的价格,即,日志(价格为1.0001)为核心合同增加了存储的空间。降低当前激活状态,即1/算术的平均平均值和几何平均值

V2的方法是直接记录价格的累积值,然后在使用时将时间间隔划分。

因此,V3的公式公式需要如下更改:

a(t)是时间t时的预测计算机的值(累积价格的日志值)。

$$ at = \ sum {i = 0}^tlog(p_i,1.0001)$$

实际上,在这里的日志值后面有一个时间间隔,每秒的累积值。

$$ += tick {} * delta time \ += tick {} *({} - {})$$

使用外部用户,将价格P(T1,T2)从T1加权到T2时间。

$$ a {t2} -a {t1} = \ frac {\ sum {i = t1}^{t2} log {1.0001}(p_i)}} {t2-t1} $$

$$ log {1.0001}(p {t1,t2})= \ frac {a {t2} -a {t1}}} {t2-t1} $$

$$ p {t1,t2} = {1.0001}^\ frac {a {t2} -a_ {t1}} {t2-t1} $$

平均几何平均值的原因:

平均几何平均水平更好地响应实际价格,这受到短期波动的影响较小。

我只是模拟.IPYNB中的平均计算数量和几何平均先知机制。

流动性先知

与V2相比,任何时间的活动是池中的流动性总数(因为它是全价范围)。

$$ += delta time /({> 0})\ += delta time / 1({= 0})$$

(因为它可能是0,所以分母目前为1)

这里的具体含义是,每个单位的流动性是城市的持续时间,也就是说,参与时间的流动性越多,每个单位的流动性越短,收入量的流动性量就会增加,反之亦然。

它的记录机制与价格逻辑一致,并且不会重复。

通过tick上的辅助预言机计算的数据

每个初始化的刻度(增加流动性),不仅是流动的数字和与成本相关的变量(,,),城市策略也有三个。

tick变量列表:

名字含义

流动性量的净内容

流动性总数

8

收取的总费用总额

8

收取的总费用总额

价格的总时间

价格价格的价格是累积的

价格的每个单位的流动性正在参与持续时间

解释了参考费的含义。这些变量的前几个是处理费的一部分,最后三个是与先知有关的数据。

如何使用刻度辅助预言机的变量:

:利用自池以来的总时间来最大程度地减少价格范围两侧的变量,您可以在价格间隔的两个侧面上获得市场的总长度:除了在市场时间的情况下,您还可以在每个间隔的平均价格(tick inter)的范围内获得限额的范围。乘以流动性的数量,城市的持续时间是您的流动性参与来提取的。

三个月前,我从白皮书开始就加入了Dapp学习的小组。

Dapp-是一个完整的开源区块链开发教程(欢迎使用Star)。

:学习结果视频共享(帐户dapp):学习结果视频共享(电台B帐户):dapp-帐户:

捐款:

参考文章

提醒:请联系我时一定说明是从浚耀商务生活网上看到的!