现代稳定币 - Liquity V2 是如何构建的

  • mixbytes
  • 发布于 2025-02-22 23:22
  • 阅读 33

Liquity V2是一个基于算法的稳定币协议,提供利息为零的借贷和低抵押率,允许用户用ETH作为抵押铸造LUSD。同时,Liquity V2引入了新稳定币BOLD,支持液态质押代币等多种抵押类型。本文详细探讨了Liquity V2的工作原理、核心机制和项目结构,适合DeFi开发者深入了解该协议的创新之处和技术细节。

image.png

介绍

Liquity V2是一个算法稳定币协议,建立在Liquity V1协议的基础之上,允许用户使用ETH作为抵押品铸造LUSD稳定币。其定义特征包括无利息借款和低抵押比率。

Liquity V2通过引入新稳定币BOLD来增强LUSD的能力,为用户提供了更强的功能。这些功能包括对新的抵押类型的支持,例如Liquid Staking Tokens (LSTs),集成的BOLD质押,用户自定义的利率,减少治理的作用,以及一些其他创新,改善协议的灵活性和去中心化。如我们之前文章的一篇中提到的,现代协议旨在创建更少治理、更无许可的DeFi市场,以促进更大的去中心化。Liquity V2通过最小化对中心化资产(如USDC/USDT)的依赖、减少治理、采用不可变合约,以及实施独特的稳定机制来追求这些目标。

这些机制值得DeFi开发者理解。为了开始我们对算法稳定币协议的回顾,我们选择Liquity V2作为一个优秀示例。让我们探讨Liquity V2是如何工作的。一起深入了解吧!

高层次评审

BOLD的基本生命周期与其他稳定币相似:

  1. 借款人 - 借款人使用ETH/LST代币作为抵押品借出贷款,铸造BOLD稳定币,并看到其债务不断增加。他们可以偿还债务或由赎回者/清算人偿还。
  2. 质押者 – 质押者锁定BOLD代币,并从借款人的不断增加的债务中赚取收益。
  3. 赎回者/清算人 – 赎回者和清算人监控借款人的头寸,并通过赎回和清算两种机制以固定价格兑换BOLD代币换取抵押品。

Liquity V2的锚定稳定机制的核心概念基于用户自行设定的可变借款利率。利率较低的头寸为BOLD质押者产生较少的收益,而如果此类“低利率”头寸较多,则对BOLD(及其价格)的需求 decreases。当价格跌破$1时,将触发“赎回”。这些赎回使BOLD能够以固定价格$1兑换为ETH/LST,提供了一个盈利机会,当价格低于$1时。赎回必须从利率最低的头寸开始,将其从市场上移除:

消除这些“低利率”头寸增加了BOLD质押者的收益,这反过来又提高了对BOLD(及其市场价格)的需求。随着BOLD价格的上涨,赎回相关的风险减少,让用户能够以更低的利率借出BOLD。这创造了一个自我强化的循环:

稳定过程在白皮书中有更详细的解释。

Liquity V2还结合了许多其他机制,例如用于不同操作的孤立池(例如,处理多余金额、煤气补偿和代币再分配)、利率调整频率的限制、“冷却”赎回费用、响应预言机或抵押比率问题的自动关闭抵押分支,以及其他创新特性。

让我们看看这些是如何构建的。

项目结构

我们将分析BOLD代码库,它包含了BOLD稳定币的完整代码(和一个有用的概述):

BOLD是一个多抵押协议,每种抵押资产(在部署时硬编码)都有自己专用的合约集。这些合约处理所有与借款相关的逻辑,包括抵押债务头寸(称为Troves)的创建和关闭,以及其分组(批次)、清算和赎回流程、费用管理,以及在不同池之间累积“中间”余额。

多个抵押分支的组合通过主CollateralRegistry合约来管理,其主要功能是在所有分支间处理赎回过程(清算则在各自的分支内独立进行)。

每个抵押分支使用自己的抵押资产(ETH或LST)进行操作。它包含TrooveManager合约,负责管理与Troves(包括清算)相关的操作,按排序列表组织。BorrowerOperations合约提供访问给定抵押分支内所有外部函数的接口。

用户通过存入抵押品和铸造BOLD稳定币来创建、关闭和调整他们的抵押债务头寸(Troves)。他们可以选择自己的借款利率,注意到较低的利率会导致更高的Troves被赎回的风险。已累积的借款利息会复利,并以75/25的比例分配给BOLD质押者和InterestRouter,后者为外部DEX上的BOLD流动性提供者提供奖励。

如果一个Troves的利率较低,它就会受到赎回约束。如果一个Troves的抵押不足,它就会被清算。这导致一个挑战:清算人需要获取BOLD代币来偿还用户的债务。这种对BOLD代币的需求推高其价格,使得抵押品变得更便宜,从而导致更多的抵押不足头寸。为了解决这个问题,在清算过程中,Liquity V2首先使用质押的BOLD代币。这些代币在市场上并不存在,因此与它们有关的操作不会影响BOLD代币的市场价格。质押的BOLD代币被销毁,而抵押品则添加到“质押”池(StabilityPool)中。因此,BOLD质押者最终会拥有较少的BOLD代币,但应收的抵押品会更多。只有当StabilityPool完全耗尽时,清算人才会转向市场上现有的BOLD代币。这一多步骤清算流程是Liquity V2的一个独特特性。

这种赎回、清算和质押的结构要求Liquity V2拥有“抵押分支”合约包,其中包括多个用于不同目的的池:质押、代币再分配、抵押 surplus和平米清算人的Gas补偿。我们将在后面详细讨论这些内容。

现在,让我们继续我们的技术回顾,考察BoldToken合约。

BOLD Token

BOLD代币在BoldToken.sol中实现,并遵循标准的ERC20接口,增加了permit功能。它支持所有标准的ERC20功能,并提供额外功能,包括:

  • mint() 函数,只能由borrowerOperations或ActivePool合约调用。
  • burn() 函数,只可由collateralRegistry、borrowerOperations、troveManager或stabilityPool合约调用。
  • sendToPool()/returnFromPool() 函数,允许将BOLD代币发送到/从StabilityPool中检索。这只能通过Stability Pool合约调用。

BOLD代币的实现有意保持与ERC20相关的功能简单,以确保该代币对于日常使用仍然高效和便捷。

抵押分支(branch)

抵押分支由一组处理单一类型抵押的合约组成。每个抵押分支包括以下组件:

TroveManager:负责管理用户头寸(Troves)和Troves组(Batches)的合约,同时跟踪每个用户的抵押金额、债务、质押BOLD代币和利率。TM还监督赎回和清算。

BorrowerOperations:提供管理Troves和Batches的功能的合约,例如创建、更新或删除它们,添加抵押品,提取债务,修改利率,将其分组为Batches,及其他操作。

ActivePool:存储与Troves和Batches相关的抵押和BOLD代币余额的合约。

StabilityPool:一个重要的合约,用于存储用户的质押,持有BOLD代币以及从清算中获得的抵押品,并为持有者积累利息。

其他合约:

DefaultPool:一个在清算过程中持有BOLD代币和抵押品“中间”余额的合约。它临时存储待分配的BOLD和抵押品的“待处理”金额。

CollSurplusPool:一个持有清算产生的多余抵押的合约。如果清算后还留有任何多余,Troves的拥有者可以追回该多余部分。

GasPool:一个持有借款人贡献的WETH余额的合约,以覆盖其Troves清算的潜在Gas费用。

首先,我们将审查TroveManager.sol合约,负责管理用户的位置并促进赎回和清算,该协议的主要稳定机制。

TroveManager

TroveManager合约管理的用户位置被表示为NFT(在TroveNFT.sol中的示例)。这些位置适用严格、不可变的抵押比率限制,确保当抵押比率达到指定阈值时,禁止借贷或提取抵押品。

核心的Trove 结构包含抵押、债务和质押的值,分别表示存入的抵押品、借出的债务和在StabilityPool中的质押。涉及Liquity V2中“抵押 <-> BOLD”的操作可以同时影响所有三个值。

Trove结构还包括其他重要属性,例如最后更新的时间(用于计算应计利息)、annualInterestRate(用户选择)和batchDebtShares — 代表该Trove在名为Batch的更大实体中的份额。一个Batch将多个共享同一利率的Troves分组。Batch为希望不单独管理其利率的Trove所有者提供益处,使他们能够将这一责任委托给批次管理者。批次管理者是一个可信地址,可以为Batch内所有Troves调整利率,并获得批次管理费。在获取最新的Batch数据的函数中可以找到Batch使用实例。这个函数从一个单独的Trove中提取数据,而是使用trove.batchDebtShares来计算 Trove的绝对债务及相关的批次管理费用。

需要提及的另一个重要地方是关于抵押分支关闭的处理(将在稍后讨论)在Trove的利率计算中。如果一个分支被关闭,协议需要使用适用于Trove利息积累的正确利息区间。

TroveManager的主要函数是redeemCollateral()和_liquidate(),但在讨论与借款操作和抵押池有关的其他合约之前,了解这些是非常实际的。

“僵尸” Troves

在Liquity V2中,债务低于MIN_DEBT(2000 BOLD)的Troves成为“僵尸”Troves。因此,最低借款额度设置为MIN_DEBT。

“僵尸”Troves主要在赎回后产生,它们不会像清算那样“关闭”Troves。从借贷的角度来看,赎回充当了针对“健康”头寸的“清算”。在赎回之后保留Troves确保赎回不会降低TCR。此外,活跃的“小”Troves存在潜在的恶意攻击,即攻击者用微小的债务堵塞排序列表。为了解决这个问题,赎回低于MIN_DEBT的Troves将被标记为无法赎回,移出排序列表,只有当所有者将其债务增至超过MIN_DEBT时,才能再次变得可赎回。有关这些不可赎回Troves的原因在这里有详细说明。

BorrowerOperations

接下来要审查的合约是BorrowerOperations,其主要功能涉及Troves和Batches的创建、修改和关闭。Liquity V2提供了广泛的Troves操作功能;在这里我们将关注最重要的方面。

首先,让我们检查安全关闭机制,控制变量为不可变的阈值:CCR、SCR和MCR,分别代表Critical、Shutdown和Minimal抵押比率:

  • 到达SCR(关闭)抵押比率将使BorrowerOperations切换到关闭模式,限制所有借款操作并仅允许关闭Troves
  • 达到CCR(关键)抵押比率时,会禁用部分借款操作(例如,开启、调整或关闭Troves),但仍允许改变利率、偿还债务以及任何改善抵押比率的调整
  • MCR(最低)抵押比率用于限制单个Troves(在开启/调整Troves操作中)。

每次Troves的调整都涉及强制性的检查,以确保更改保持单个抵押率ICR > MCR和总分支抵押比率TCR > CCR。

通过“独立”的openTrove()函数或openTroveAndJoinInterestBatchManager()来创建Troves,将新Troves添加到Batch。这两者最终调用内部的_openTrove()函数。让我们探讨一下这个机制。

首先,我们需要解释什么是“加权债务”。这些数值经常在Liquity V2中出现(例如,这里)并且是通过应用年利率来评估的债务(例:100$,利率10%=110$,与101$,利率5%=106.05$)。这个值在决定费用和估算Troves“价值”时起着重要作用。它会在债务更改时更新(例如,在Troves创建、调整、利率更新、赎回和清算等过程中),用于计算整个抵押分支的加权平均利率(例如,通过getNewApproxAvgInterestRateFromTroveChange()函数)。

另外一个需要描述的重要组成部分是前端费用,线性依赖于池的总平均利率。池中的更高利率对应于更高的前端费用。

让我们继续创建一个Troves。后续的检查确保这个费用不会超过用户准备支付的金额(滑点保护)。接下来,检查MIN_DEBT

后续步骤包括对“加权”债务的计算和支付批次管理费(如果需要),检查最低抵押比率,和对整个抵押分支的新总抵押比率的计算(这包含新债务、抵押和费用进总储备)。

接下来是“添加”和“删除”管理者的委托。Liquity V2允许第三方Troves管理,委托账户可以执行镜像操作。addManager可以添加抵押品和偿还债务(提高抵押比率),而removeManager可以提取抵押品和借出债务(降低抵押比率)。这个特性便利了Liquity V2与外部头寸管理系统的整合。

另一个重要步骤是对广泛使用的mintAggInterestAndAccountForTroveChange()函数的调用,更新ActivePool中的总债务相关值(包括所有Troves债务和抵押余额的直接和“加权”总和),以及前端费用。

最后一系列交互遵循检查-效应-交互模式,启用从用户那里提取抵押品放入ActivePool、铸造用户的BOLD代币,以及转账一些WETH到GasPool,以覆盖清算的Gas费用。

完成内部的Troves开启工作流程后,外部函数可以铸造TrovesNFT,不论是“独立的”或是“加入批量”的Troves。独立Troves铸造的示例在这里。对于通过openTroveAndJoinInterestBatchManager()加入批量的Troves,Troves 也会加入一个Batch。由于Troves按利率排列,Batch只是使用排序列表中的“头”和“尾”指针(如insertIntoBatch()函数演示于SortedList.sol中)。

下一个重要函数是_adjustTrove(),其工作原理类似于_openTrove,但可在两个方向上调整抵押和债务,并在现有Troves上处理不同的操作。该函数在addColl()、withdrawColl()和repayBold()函数中使用。

函数_adjustTrove()以关键的检查开始验证预言机的活跃性和抵押分支的TCR阈值。随后,它包括对Troves管理者的访问控制检查、调整中的限制检查以及最终的债务和抵押的更新。对于在Batch中的Troves需要更复杂的更新

过程结束与_openTrove相似,并且结束,通过铸造利息(在每次“触碰”Troves时执行)以及铸造/销毁/转移适当数量的BOLD和抵押代币完成。

一个独特的函数是adjustTroveInterestRate(),用于调整Troves的利率。由于需要重新计算“加权”债务、收取因债务变化的前端费用,并重新插入Troves进排序列表,这在Liquity V2中并不简单。该变更仅适用于独立Troves而且

此外,中间的函数applyPendingDebt()应用利率到Troves债务的。在某些情况下,此操作可以增加“僵尸”Troves的债务,将它们放回排序列表并移除其“僵尸”状态。

closeTrove()中关闭一个Troves相对简单,这得益于对先前函数的理解。该操作为结束销毁BOLD代币、提取所有剩余抵押并以WETH返回Gas补偿。

BorrowerOperations中的其他函数处理Troves管理者配置,允许他们管理债务、抵押、利率变化或成为Batch管理者。Liquity V2最小化治理功能,并且BorrowerOperations中没有治理相关的逻辑。

ActivePool

ActivePool合约负责持有BOLD和抵押代币的余额,这些余额由Troves管理。从另一种角度看,AP可以被视为一个大型“汇聚”Troves,整合所有Troves的所有抵押和BOLD余额。

如前所述,ActivePool处理接收和发送抵押和BOLD代币。特别是,关键功能涉及移动抵押和BOLD代币。sendColl()函数将铸造外部,例如在redeemCollateral中(将抵押品发送给赎回者)或在清算期间将多余抵押发送到CollSurplusPool。相反,通过receiveColl()函数接收抵押。

Stability Pool

StabilityPool合约是稳定机制的重要组成部分。这是BOLD持有者质押其BOLD代币以从利率和清算中获得收益的池。如前所述,在清算过程中,首先会燃烧BOLD代币。

该池发挥双重作用:实现了BOLD质押功能,同时允许用户索取因清算而没收的抵押品。当一个Troves被清算时,其债务实际上被移除,等量的BOLD在Stability Pool中被销毁。同时,没收的抵押品转移到Stability Pool,必须在存款者之间进行再分配。该过程要求合理地降低所有存款者的BOLD余额并增加他们的抵押余额。同样,池中产生的利息也必须在BOLD持有者之间进行分配。

在DeFi背景下,迭代存款是低效的,因此Liquity V2采用了其论文中说明的分配方案。关键思想是,每次 i-次清算之后(当BOLD的totalSupply减少,并且Stability Pool中的totalSupply抵押增加时),个别存款的价值可以根据其先前价值和清算的BOLD比例进行更新(amountLiquidated/totalSupply)。简单地说,如果BOLD的totalSupply减少了5%,那么个别的BOLD存款也应该以同样的比例下降。通过从初始的“零时间”存款开始逐次应用这一减少,最终形成了一个迭代计算方案:

其中 d₀ 是在 i=0 时的初始存款, Qᵢ 是第 i-次清算期间清算的BOLD数量, Dᵢ 表示第 i-次清算时BOLD的totalSupply.

因此,在每次随后的清算之后,我们可以“复利”比例减少(用红色标记),只保留每个存款的 d₀ 值。同样通过保持累积的减少比例(用橙色标记),我们能够通过一次简单的乘法来计算第 n-次清算时存款的“当前”价值。

类似的逻辑应用于没收的清算数额(此处省略详情,但已在论文中解释)。在第 t-次清算中获取抵押的最终公式为:

其中 d 为第 t-次清算的存款, S S 为清算金额快照(每个存款的存储和更新),而 P 是BOLD“总供应累积差”的累积乘积(如前所述)。

同样的方法用于计算BOLD产量收益,这会按比例增加质押者的BOLD存款(利用另一个 B 分类在快照中)。

因此,该系统确保每次清算或收益事件仅更新很少(三个)累加器在StabilityPool的快照中。这些累加器在存款者的余额“触碰”时用于重新计算后续“锚”值。该方案运作以O(1)的复杂性,确保清算和存款相关操作的持续Gas费用。

计算乘法时,使用值在[0,1]范围内(如 1−Q ₊₁/D )在EVM中存在缺陷。需要对累积乘积进行缩放以保持精度。此外,当池为空时会出现极端情况,导致BOLD的totalSupply为零。这种情况需要通过引入“纪元”进行处理,纪元每次在池完全耗尽时递增。这些操作的累加器存储在 Snapshots 结构中,而“每个存款”的值则维护在 三个 映射中。

函数 getDepositorCollGain() 实现了上述公式,用于计算特定存款人从清算中获得的扣押抵押品收益。它 使用 Snapshots 的 “S” 部分。如可以观察到,这些计算是直接且节省 Gas 的。第二个函数 getDepositorYieldGain() 的操作类似,但 使用 Snapshots 的 "B" 部分。

provideToSP() 函数是针对 StabilityPool 的特定存款人的 BOLD “存款” 操作。它 收集 来自 ActivePool 的累计利息,调用 上述两个函数以确定 BOLD 收益和扣押抵押品收益,并 计算 应发给存款人的 BOLD 和抵押品金额(如适用)。然后,在 _updateDepositAndSnapshots() 函数中,它 更新 存款人的快照累加器,并 转移 “in” 或 “out” 代币(BOLD 和抵押品),同时更新池中 BOLD 和抵押品的总金额。“withdraw” 函数 withdrawFromSP() 遵循相同的逻辑,收集来自 ActivePool 的利息,更新存款人的快照,并将结果金额转移到存款人。

我们无法审查 StabilityPool 数学的每个方面,涵盖潜在的边缘情况,但这些计算的结果是设计简洁的功能来管理质押者的 BOLD 和抵押品收益。

DefaultPool 和 CollSurplusPool

这两个池充当 “中介” 组件。它们不是 BOLD 稳定机制的核心部分,但处理在赎回和清算中产生的 BOLD 和抵押品金额。这些金额必须重新分配(DefaultPool)或被暂时保留(CollSurplusPool)以供以后取回。

这些池的实现很直接。DefaultPool ool 只是简单地 追踪 其 BOLD 债务,持有抵押品,并 根据需要转移 给 ActivePool。

CollSurplusPool 持有抵押品代币的 余额,通过将来自清算的过剩存入 Trove 所有者的余额中来 增加 它,并允许所有者 在稍后认领 这些资金。

风险管理

现在,在审查了 “基础” 合约(TroveManager、BorrowerOperations、ActivePool、StabilityPool)以及额外的 DefaultPool 和 CollSurplusPool 后,我们可以研究主要的稳定机制:赎回和清算。

赎回

赎回是通过 redeemCollateral() 函数执行的。该函数代表了在每个 TroveManager 内的 CollateralRegistry 中的 redeemCollateral() 循环中的单一步骤,其中该过程 跨越 多个抵押分支进行执行。

在特定的抵押分支中,此函数遍历多个 Troves,燃烧 BOLD 债务并赎回抵押品,旨在满足赎回者指定的 remainingBold 数量。该遍历使用按利率排序的 Troves 列表,从利率最低的开始,如白皮书中所述。

处理的第一个 Trove 是排在排序列表的 最后。选择排序列表中的最后一个 Trove 足以识别出利率最低的 Trove。

接下来,将在排序的 Troves 上 启动 循环,该循环受到 _maxIterations 限制,这是由赎回者定义的参数,旨在防止 “out-of-gas” 错误。在每次迭代中,将使用赎回者提供的 _price 计算 Trove 的 ICR(个人抵押比例),确保 Trove 的 ICR 不低于 100%。ICR 的计算简单明了,已在函数 _computeCR() 中实现。

如果 Trove 属于一个包含其他 Troves 的批次,则会 更新 批次的利率(仅更新一次,因为批次内的所有 Troves 共享同一利率)。最后,从 Trove 中 赎回 抵押品,通过调用 _redeemCollateralFromTrove()。在此函数内部,计算出 赎回费用(以抵押品代币计),并更新 Trove 的抵押品和债务金额。如果该 Trove 属于一个批次,则该批次也会被更新。如果 Trove 的最终债务变得微不足道,则该 Trove 将被 标记 为 “僵尸”,并随后从该批次中删除。

在每次循环迭代结束时,赎回的抵押品总金额和 BOLD 代币移除的总金额会 更新,同时累积赎回过程中的前期和当前债务。

在足够的 Troves 被赎回后,累计的利息费用会 铸造Stability Pool(75%),使 BOLD 质押者受益,并铸造到 Interest Router(25%),以激励外部 DEX 上的 BOLD 池。然后,批次管理费用 支付 给受影响的批次的管理者。

最后一步是将 赎回的抵押品发送 给赎回者。

清算

第二个核心稳定机制是清算。我们来审查内部的 _liquidate() 函数,它是所有清算的基础。

首先,我们 处理 Trove 中任何未分配的债务和抵押品收益。然后,向清算人提供 Gas 补偿。该补偿 等于 正在清算的抵押品的 1/200,最高上限为 2 ETH(常量在这里 定义)。

在 Liquity V2 中,清算优先使用来自 StabilityPool 的 BOLD 余额(在 SP 中燃烧 BOLD,同时将扣押的抵押品转移到其中)。如果 SP 的 BOLD 余额不足,则将使用清算人的 BOLD 代币,抵押品和 BOLD 在 Troves 之间分配。Liquidated Trove 中的任何剩余抵押品被转移给 CollSurplusPool,可以被该 Trove 的所有者认领。

清算过程首先 确定 StabilityPool 和再分配的比例。这些金额是通过 首先 评估 “StabilityPool” 部分,然后评估 “redistribution” 部分 来计算(在分配机制回顾中已讨论过)。

接下来的步骤是使用 _closeTrove() 函数 关闭 Trove。该 Trove 将从排序列表中 删除,并对批次或“僵尸” Troves 进行额外处理,同时更新 totalStakes 值。该 Trove 还会从主 Troves[] 映射中删除,相关的 TroveNFT 也会被移除。此后,将 支付 批次管理费用(如适用)。

剩余的抵押品随后被 发送 到 CollSurplusPool,该池积累了多余的抵押品,并使 Trove 所有者能够认领。

最后,清算过程通过 移除 _troveId 从与 Trove 管理相关的各种映射中完成。

抵押登记

现在,我们可以结合抵押分支并审查 CollateralRegistry 合约,该合约将协议的所有抵押分支汇聚在一起。它保存多个(最多 10 个)不变的抵押资产地址及其相应的 troveManager 的配置。

从多个抵押分支赎回抵押品是 collateralRegistry 合约的主要功能(清算在抵押分支中独立管理)。赎回是在 redeemCollateral() 函数中执行的,该函数 遍历 多个 troveManagers,尝试赎回抵押资产。该函数还燃烧相应数量的 BOLD 代币,并更新 baseFee。每个抵押分支分配的赎回金额与该分支的 “weight” 成正比,其中 “weight” 是其 在整个协议总债务中的比例。例如,如果三个分支占总债务的 10%、20% 和 70%,则总可赎回的金额将在各抵押分支之间按 10%、20% 和 70% 的比例分配。此 “赎回路由” 在 此处 描述。

该合约中的一个重要值是 baseFee,它用于计算赎回发生时适用的赎回费用。该费用在每次进行新的赎回时都会 变化,并取决于被移除抵押品的比例(在下文 “费用” 部分描述)。

费用

费用在 DeFi 协议中的作用不仅是提供激励,还有助于防止某些危险场景的发生。Liquity V2 使用不同类型的费用。让我们讨论一下它们。

第一种费用是“前期费用”。该费用以 BOLD 代币形式收取,基于债务进行计算。它适用于每一个增加总债务的操作,包括 _openTrove()_adjustTrove()adjustTroveInterestRate()。最后一个操作也需支付前期费用,因为利率变动会改变“加权债务”,而这在许多计算中都会用到。此外,在最后的情况下,前期费用有一段“宽限”期,即 7 ,且只有在此期间内作出变更时,费用才会生效。这一机制保护协议免受“赎回规避”的风险,即借款人在发现赎回风险时可能临时改变利率,或关闭再重新开启其 Trove。

另一种费用是由特定批次的管理者收取的批次管理费(该费用的大小由管理者自行设定)。它的运作方式类似于 BOLD 利息,根据一个批次中 Troves 的债务计算年利率。我们将不再详细探讨这类费用,因为它相对简单。

下一项费用是赎回费用,其具有趣味性的放宽方案如下所示:

橙色线表示 baseFee,用于计算赎回过程中作为费用收取的抵押品金额。每个蓝色条表示一次赎回,它的高度表示赎回的金额。当发生赎回时,该费用会“被推高”,然后再“冷却”直到下次赎回。这种行为在 函数 中实现。设计这一机制的目的是为了阻止大规模赎回和随之而来的赎回,通过施加更高的费用来抑制此种行为。此外,此费用有一个 0.5% 的底线。

实现细节

像许多其他算法稳定币一样,Liquity V2 依赖于价格预言机(由 Chainlink 提供)来确定当前抵押资产价格。这些预言机在 PriceFeeds 模块下实现。

Liquity V2 一个显著的特点是使用“提示”来管理排序列表中的 Troves。所有 Troves 都组织在一个排序列表中,因此将项目插入或重新插入该列表需要多次迭代,这会消耗额外的 Gas。为优化这一过程,用户可以指示协议从被称为“提示”的特定元素开始搜索(具体示例见 这里)。为了帮助用户提供提示,HintHelpers.sol 合约中还包含了一个特殊的视图函数 getApproxHint()

我们几乎忘记了 GasPool,但它的作用仅仅是持有 WETH,用于补偿液化者的 Gas,在 TroveManager 中 这里 可以看到。

结论

Liquity V2 及其 BOLD 稳定币代表了一个有趣的项目,利用以 ETH 为支撑的资产作为抵押,避免了使用中心化的 USDT/USDC。其稳定机制基于赎回和清算。Liquity V2 稳定逻辑的聪明之处在于将 BOLD 质押、清算和赎回结合成一个单一的机制。在此,燃烧 BOLD 和收回抵押品重新分配 StabilityPool 中的资产,自动平衡用户持有的稳定币和抵押品数量。

Liquity V2 的突出机制包括:

用户设定的借款利率

用户 Troves(抵押-债务头寸)按照利率在排序列表中组织

当 BOLD 价格低于 $1 时赎回(清算以固定的 1 对 1 像素进行)

ᅠ◦ 从利率最低的 Troves 开始,逐步消除这些头寸,从而增加 BOLD 收益和需求

BOLD 价格高于 $1 时进行清算

ᅠ◦ 通过燃烧 BOLD 并将抵押品加入 StabilityPool 来实现,减少 BOLD 收益和需求

在 StabilityPool 进行 BOLD 质押,结合借款利率和清算同时产生的收益

在赎回中结合多个抵押分支,将赎回金额按 “每个分支”的债务进行分配

Liquity V2 还具有多种附加功能,如将 Troves 分组为批次,委托 Troves 和批次的管理,Gas 补偿,自动保护抵押率,以及许多其他创新解决方案。

这个项目无疑值得研究,作为算法稳定币的示范性实现。因此,它被包含在我们的“稳定币”系列文章中。下次再见!

  • MixBytes 是谁?

MixBytes 是一支专业的区块链审计和安全研究团队,专注于为 EVM 兼容和 Substrate 的项目提供全面的智能合约审计和技术咨询服务。请加入我们在 X 上,及时了解最新的行业趋势和见解。

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

0 条评论

请先 登录 后评论
mixbytes
mixbytes
Empowering Web3 businesses to build hack-resistant projects.