Uniswap V2 如何计算 mintFee

本文详细介绍了Uniswap V2中协议费的收集机制,包括费用计算的数学公式、代码实现以及影响因素。文章还指出了在流动性提供者调用mintburn时收集费用的效率问题,并通过示例和代码片段深入解释了_mintFee函数的工作方式。

Uniswap V2 旨在将 1/6 的交换手续费收归协议。由于交换手续费为 0.3%,因此 1/6 的手续费为 0.05%。所以每笔交易的 0.05% 将会归协议所有。

尽管这个功能实际上并没有被激活,但我们还是讨论这个功能,毕竟一些分叉可能会使用它。此外,这个计算很容易出错,现在花时间理解它将有助于你在类似计算中捕捉错误。

先决条件

你需要熟悉 Uniswap V2 Book 中的所有前面的章节,才能跟上后面的内容。

在交易过程中收集协议手续费效率低下

在每笔交易中收取 0.05% 的手续费效率低下,因为这需要额外的代币转移。转移 ERC20 代币需要更新存储,因此将代币转移到两个地址而不是一个会产生更高的成本。

因此,当流动性提供者调用 burn 或 mint 时收取手续费。由于这些操作相对于 [交换代币](swapping tokens) 来说是不频繁的,这将节省 gas 费用。为了收取 mintFee,合约计算自上次发生以来收集的手续费,并铸造足够的 LP 代币到受益地址,使受益人有权获得 1/6 的手续费。

费用和 mintFee 的术语

为避免术语混淆,我们将“费用”称为在交换过程中从交易者那里收取的 0.3%,而“mintFee”则是 0.3% 费用的 1/6。是的,这两者都使用费用这个词并不是很好,但这就是我们必须处理的内容。

流动性是池中代币余额乘积的平方根。这个公式的理由在 Uniswap V2 交换函数文章中有所讨论。一些文献将其称为 $\sqrt{k}$,其中 $k = xy$,$x$ 和 $y$ 是池中的代币余额($x$ 和 $y$ 的储备)。我们用 $\ell$ 来表示流动性,因为它写起来比 $\sqrt{k}$ 短。

计算 mintFee 的假设

为了使这个有效,Uniswap V2 依赖以下两个不变性:

  • 如果没有调用 mint()burn(),池的流动性只能增加。
  • 流动性的增加仅仅是由于手续费(或捐赠)。通过测量自上次 mint()burn() 交易以来流动性增加的情况,池知道收集了多少手续费。

这些将是写好的 不变性测试,但目前我们将理所当然地认为它们是真实的。

mintFee 示例计算

假设在 $t_1$ 时池中有 10 个 token0 和 10 个 token1

经过大量交易和手续费收集后,$t_2$ 时新的池余额为 40 个 token0 和 40 个 token1

流动性被测量为两个代币的乘积的平方根,即 $\ell = \sqrt{k}$。在 $t_1$ 时流动性为 10,在 $t_2$ 时流动性为 40。反过来说,$\ell_1 = 10$ 和 $\ell_2 = 40$。我们将对从 10 增长到 40 的部分收取手续费。

在 $t_2$ 时,总共 40 的流动性中有 30 单位是由于交换手续费。

我们想要铸造足够的 LP 代币,即“mintFee”,使得受益人可以获得池中“费用部分”的 1/6。也就是说,他们应该有权获得 5 单位的流动性 (30 / 6),这是来自利润的。

协议不应收取任何“原始流动性”的费用,即 $\ell_1$。协议应仅收取增量的费用,即 $\ell_2 - \ell_1$。

当调用 mint()burn() 时,Uniswap 为协议费用接收方铸造 LP 代币。这会导致稀释,使得 当前供应 的 LP 代币可以赎回原始流动性加上 5/6 的“利润流动性”(来自交换手续费的流动性)。

推导 mint fee 公式

让我们使用以下符号:

  • $s$ 为稀释前的 LP 代币供应量。

  • $\eta$ 为将铸造到协议的 LP 代币数量。它应足以进行 1/6 的利润流动性的赎回。

  • $\ell_1$ 为原始存款的流动性,即 LP 提供的流动性。

  • $\ell_2$ 为原始存款的流动性以及由于交换手续费而得到的流动性。

  • $d$ 为除去协议手续费后应支付给 LP 的流动性金额。也就是说,LP 应获得其原始存款和 5/6 的利润。

  • $p$ 为协议应获得的流动性金额。这是 5/6 的 $\ell_2 - \ell_1$。

要计算 $\eta$,我们观察到以下不变性必须为真:

$$ \frac{\eta}{p}=\frac{s}{d} $$

换句话说,前总供应量 $s$ 的 LP 代币可以赎回应给 LP 的流动性,而 $\eta$ 的 LP 代币可以赎回应给协议的金额。

下图解决了关于流动性变化时 $\eta$ 的推导问题。

protocol fee 的代数推导

Uniswap V2 的 _mintFee() 代码

考虑到这个推导,Uniswap V2 的大部分 _mintFee 函数应该是不言自明的。以下是一些符号的变更:

  • 收费后的当前流动性 $\ell_2$ 为 rootK
  • 先前流动性 $\ell_1$ 为 kLast
  • 稀释前的 LP 代币供应量 $s$ 为 totalSupply
  • 该函数是状态改变的,它在函数内部铸造 mintFee,而不是返回 mintFee 的计算(蓝色高亮)
  • 费用可以通过 feeOn 标志开关,该标志我们尚未讨论

_mintFee\(\) solidity 代码

我们将进一步深入讨论此功能,但首先我们想指出 kLast 是在哪里更新的。

kLast 更新的位置

在上面的代码中,kLast 只有在 feeOn 设为 false 时才会设置。它在 mint 和 burn 完成时设置,但不是在 swap 时设置,因为我们希望测量由于交换而引起的流动性增长,涉及存款和取款事件。从标记的黄色框中可以看到设置 kLast 的位置。

Mint 函数更新 kLast

Uniswap 的 mint 函数,列出了费用开关

Burn 函数更新 kLast

Uniswap 的 burn 函数,列出了费用开关

_mintFee 代码条件

现在我们理解了 kLast 如何更新,我们可以充分解释 _mintFee 函数。 _mintFee 函数在分支点高亮

让我们考虑上面代码片段中的可能性,重复以方便理解。

  1. feeOnfalse,什么都不会铸造(绿色高亮)
  2. feeOnfalsekLast 为零(黄色高亮)
  3. feeOnfalsekLast 不是零(黄色高亮)
  4. feeOntrue,但流动性没有增长(橙色高亮)
  5. feeOntrue,并且流动性有所增长(橙色高亮),因此适用铸造费用(蓝色高亮)

在决策树中更容易看到逻辑,因此这就是与 if 语句的分支颜色相同的决策树。

展示五个分支的 _mintFee 决策树

通过 RareSkills 学习更多

请查看我们的 区块链训练营 以了解我们的课程提供。

原始发布于 2023 年 11 月 14 日

  • 原文链接: rareskills.io/post/unisw...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
RareSkills
RareSkills
https://www.rareskills.io/