现代DeFi 借贷协议 - Aave V3 是如何构建的

  • mixbytes
  • 发布于 2024-09-20 12:25
  • 阅读 42

这篇文章详细介绍了Aave V3协议的设计和实施细节,分析了其创新的供需模式和风险管理功能,包括新的风险参数设置、借贷逻辑以及反对价格操控的机制。文章的结构清晰,涵盖了各种技术细节,并对比了Aave V2和V3的变化,使读者能够全面理解Aave V3在DeFi领域中的重要性。

简介

现代借贷的轮廓中,缺少一个最重要的项目 - Aave,无法算完整。Aave 是一个顶级的借贷协议,拥有最高的 TVL,经过完全验证的安全性和有效性。Aave V2 是我们 DeFi 教育课程中“必学”的部分,因为它创新的供应和债务代币机制设计,以及其借贷池架构。现在,让我们来探索 Aave 下一次演变——Aave V3 的实现细节。

高层设计

Aave 协议的技术设计围绕着由协议治理管理的主要借贷池,以及一组可重置的供应和债务代币用于存储用户对协议的义务。核心借贷流程 - 借款/偿还/供应/提取 - 通过协议代币的铸造/销毁与用户配置位图处理。

Aave DAO 选择抵押品和债务资产,并定义其风险参数,这使得高风险或受损代币很难被引入到协议中。但市场上需要使用许多不同资产,具有不同的风险配置。为此,V3 引入了专业的供应/借贷模式以及具有可调风险参数的资产组合。与 V2 相比,V3 的一个重要增强是增加了这些模式。“隔离”模式将供应商限制为单一资产,并限制从特定的(主要是稳定币)代币中借款。另一个特性是“效率模式”,专为价格相关的资产设计,例如以相同的“基础”资产作为价格来源的资产。例如,与美元挂钩的稳定币或以以太坊为基础的衍生品。在这些情况下,可以调整风险参数,使得供应商和借款人更具盈利性,因为许多价格操控的风险被降低了。

这些模式减轻了在供应/借贷方案中将风险资产和“安全”抵押资产“混合”的风险,允许对“安全”市场增加资本效率,在市场中创造出稳定、可预见资产和波动性高、风险大的资产之间的明确区分。

与 Aave V2 相比,V3 提供了许多附加功能,使该协议更加灵活。Aave V3 启用跨协议桥接,允许在不同网络之间桥接代币,设置供应和借款上限(保护协议免受大规模攻击),将风险管理委托给专门的代理和 DAO,实施可变清算关闭因子(允许对接近破产的头寸进行完全清算),提供多种奖励代币,以及许多在 白皮书 中详细描述的其他功能。

Aave 的主要程序围绕可重置的协议代币展开,而没有直接的“每用户”结构来管理头寸。当用户供应资产时,他们会收到 ATokens,而借款时会获得不可转让的债务代币。额外的“每用户”配置包括对抵押/债务资产的启用/禁用位以及其他配置选项。

核心

Aave V3 的主要合约是 Pool.sol 合约,其中包含借款/供应/清算/闪电贷和其他功能的入口点。它还包含一系列用于 ACLs(访问控制列表)、地址管理、协议代币、预言机合约、奖励管理控制器等的合约。这些合约的结构在 文档 中有进一步的说明。

Aave 设计中的第一站当然是 AToken。这个代币展示了一种设计,允许利息直接“在”代币余额中积累。AToken 的关键特性是其 balanceOf()totalSupply() 函数,显示每个代币持有者和总供应不断增加的余额。这种方法与 Compound 的做法不同,在 Compound 中,CToken 的余额保持 不变,利息是单独计算的。使用可重置的供应和债务代币可以方便地计算协议储备和债务,避免过多的乘法,并允许供应代币在不同地址之间移动而无需额外的逻辑。

在债务代币方面也采用了相同的方法:在 StableDebtToken.solVariableDebtToken.sol 中的 balanceOf() 函数包括复利利息。研究这些函数可以深入理解 Aave 中如何运作的稳定和可变借款利率。

[注意] StableDebt 代币已不再由 Aave 支持,根据治理的 决策

Atoken 合约(针对每个基础资产:WETH、DAI 等)也持有基础资产的余额(WETH、DAI 等)。铸造/销毁 ATokens 的过程还涉及将基础代币进出协议。这使得基础余额彼此保持分离,并降低了与通过单一合约持有所有代币余额相关的风险。

Aave V3 协议的主要逻辑部分位于多个 中。这种方法增强了代码的可组合性,使每个逻辑组件能够单独测试,而无需为每个测试完全初始化协议,这对开发和代码分析非常有益。

借款/偿还

借贷逻辑在 BorrowLogic.sol 中概述,并通过 executeBorrow() 函数执行。在对借款可能性进行了全面的 验证 后,债务代币被 铸造 到用户的地址,并将基础资产 转移 给用户。与任何修改协议储备的函数一样,借款也会 更新 市场利率,以反映新的储备金额。

executeRepay() 函数中的偿还逻辑在许多方面“镜像”借款,但有一个有趣的特征:它允许使用不仅是基础代币,还使用供应的 AToken 来偿还债务。如果借款人已经使用了借入的代币,则无需从其他地方获取这些代币——他们可以使用他们的供应来偿还债务。

V3 还实现了一项由治理设置的借款上限 限制,这对于保护协议免受利用预言机价格操控、闪电贷和巨额资金使用的大规模攻击至关重要。

供应/提取

供应逻辑在 supplyLogic.sol 库中通过两个函数详细说明:executeSupply()executeWithdraw()

在 Aave 中进行供应涉及到铸造 AToken 并 更新 市场利率以反映新的储备金额。提取过程也是对供应的“镜像”过程,销毁 ATokens 而不是铸造。然而,还有一个有趣的实现细节。AToken.sol 中的 mint() 和 burn() 函数 使用 _mintScaled() 和 _burnScaled() 函数,这些函数通过利用流动性指数来计算铸造/销毁的目标数量(用于缩放 AToken 和债务代币的余额)。在 _burnScaled() 的情况下,最终的余额变化可以是正的(如果累积的利息大于被销毁的数量),这意味着不仅仅是销毁代币,而是铸造更多的 ATokens。这种情况在使用可重置代币的 DeFi 协议中可能会发生——这是储备和利率计算极大简化的权衡。

最后的提取步骤当然包括 检查 头寸的健康系数,下面将对此进行讨论。

与借款类似,V3 现在在供应时包括了上限 限制,以保护协议免受借款部分所描述的攻击的影响。

协议储备

如前所述,Aave 使用相应的 AToken 合约的余额来存储基础代币。这种分离有助于缓解将所有资产存储在单一地址上的风险。AToken 和债务代币余额不断增加,由依据当前策略调整的指数进行缩放。updateInterestRates() 函数使用策略合约(由协议治理设置)在这里计算下一次供应/借款利率,使用当前债务、协议储备和新增/移除的流动性作为参数。该函数在所有借款/偿还/供应/提取操作中均存在,确保每当流动性金额发生变化时更新协议状态。

另两个在每个操作期间调用以更改当前使用的储备资本的全局状态的函数是 _updateIndexes()_accrueToTreasury(),这两个函数同样在每个操作期间被调用以调整协议储备。

这些全局更新对于将不同风险参数应用于每个资产以及管理稳定/可变债务率和市场策略至关重要。

预言机

对于任何借贷协议,价格预言机至关重要,提供根据市场价格比较不同资产数量的手段。在 Aave V2 中,ETH 是主要的“测量单位”,所有资产数量都转换为 ETH 以进行比较。在 V3 中,Aave 预言机支持使用任何 基础 货币单位。

Aave V3 中的预言机位于 AaveOracle.sol 合约中。关键函数是 getAssetPrice(),该函数利用 Chainlink 价格预言机,并在价格不可接受时引用 _fallbackOracle。

资产价格对于验证头寸的健康至关重要,因为它们用于根据当前市场汇率计算抵押和债务价值。预言机在 这里 中的 calculateUserAccountData() 函数用于计算用户债务和抵押,并在 validateBorrow() 中确保抵押符合请求的债务。

在清算过程中,资产价格同样至关重要,价格 用于确定所需的债务代币数量和清算人扣押的抵押品数量。

V3 的一个显著特征是 PriceOracleSentinel,它解决了价格预言机的停机或停机问题。在这些情况下,Aave 向用户提供时间以恢复其头寸至健康状态,期间会 拒绝 清算。

风险管理和清算

Aave 提供对不同资产组合的风险参数进行细粒度控制的能力,覆盖其网络。每种资产的实时风险参数仪表盘可以在 这里 找到。V3 拥有一大套这些参数,包括标准 LTC 和利率,也包括借款/供应上限。

清算过程是任何借贷协议中的关键组成部分。在 Aave 中,它在 executeLiquidationCall() 函数中实现,其中第一步是对健康系数的 计算,应用针对指定抵押资产的清算阈值限制。

V3 相较于 V2 的一个重要改变是可用的清算关闭因子的调整(清算人可以偿还多少债务)。以前设定为 50%,Aave 现在允许在头寸健康系数低于 0.95( CLOSE_FACTOR_HF_THRESHOLD )的情况下偿还高达 100%( MAX_LIQUIDATION_CLOSE_FACTOR )的债务。这一更改提高了对不健康头寸的快速清算,有助于更有效地消除潜在的坏债务。

Aave 清算过程的另一个显著特征(与偿还过程逻辑相似)是清算人可以 用 ATokens 接收扣押的抵押品。这一特性允许清算人在无须退出协议的情况下,自动将抵押品添加到其供应中。

实现细节

自定义数学库是许多借贷协议的常见做法。不同资产之间的交互、比率、百分比和不同精度资产数量的计算都需要对协议中的数学进行统一。在 Aave 中,主要库是 WadRayMath.sol,它管理溢出、精度损失,并确保乘法/除法操作的正确顺序。它运用了两种主要的精度类型:18 和 27 位。例如,rayMul() 或 rayDiv() 函数几乎在所有地方使用,而不是常规的乘法/除法,这样处理精度和运算顺序潜在问题的可能性更小。

虽然 Aave 使用协议供应/债务代币来跟踪用户的供应和债务,但这些余额本身并不够以涵盖所有逻辑方面,特别是在跟踪用户借入或供应的特定资产时。为了解决这个问题,Aave 采用了额外的“每用户”值,作为单个 uint256 存储(结构 UserConfigurationMap)。每当用户更改其头寸时,用户配置位图中的标志会变化(如 “isBorrowing” 的示例 在这里在这里)。这在操作期间需要额外的步骤(就像 这里),但它有助于在许多阶段进行验证(例如进行 validateBorrow 验证时 在这里),特别是对于 "用户是否借入任何资产" 的查询,这在没有这些配置映射时,概需要查询多个代币余额。

Aave V3 支持使用许可的操作,具有特殊版本的 supplyWithPermit()repayWithPermit() 函数,允许异步签名。这使用户能够将这些操作委托给外部账户,例如第三方提供商,如果他们不希望直接执行。

Aave V3 还引入了 L2Pool.sol 的第二个变体。它镜像了基础 Pool.sol 的功能,但接受作为打包的 bytes32 值的参数。这些值在内部由 L2Pool.sol 解码,然后转发到 Pool.sol 中的相应函数。此方法使得可以通过单一 bytes32 参数执行如 supply()borrow() 等操作,显著降低了 L2 rollups 的交易成本。

Aave V3 还引入了闪电贷的第二种变体。 executeFlashLoan() 函数与 Aave V2 类似,允许用户借入多个资产,并通过增加他们在协议中的债务来偿还闪电贷债务及费用。此外,V3 提供了简化版本的闪电贷( executeFlashLoanSimple() 函数),允许借入单一资产而不可以用“债务增加”方式支付,从而降低了 gas 成本。V3 还允许设置授权的“闪电借款人”地址,这些地址可以免于闪电贷费用。

结论

Aave V3 是一个借贷协议的典范,能够对跨多个网络的每种资产类型的风险参数进行细粒度控制,并包含各种供应/借贷逻辑模式。这种风险配置的分离允许 Aave 在高风险区域对市场条件做出反应,而不影响协议中更稳定的部分。Aave 的供应模式(“效率”和“隔离”)允许专门的风险配置,根据所涉及资产的性质(如稳定币、流动质押资产、相同基础资产的衍生品等)优化利率、借贷效率和安全性。

Aave 使用的可重置的供应和债务代币简化了流动性转移,通过简单的供应代币转移实现。这种方法简化了累积利息的计算,并允许使用供应代币而非基础代币进行操作,从而增强了清算和偿还的灵活性。用户可以使用供应代币支付债务,或者将扣押的抵押品转换为供应代币,而无需离开协议。

Aave V3 引入了供应/借款上限、预言机哨兵和委托风险管理,以增强协议对安全和金融事件的响应能力。目前,Aave 在 DeFi 领域内脱颖而出,成为最强大的借贷项目之一。我们期待 Aave V4 的未来发展。

在我们的下一篇文章中见!

  • MixBytes 是谁?

MixBytes 是一个专业的区块链审计师和安全研究者团队,专注于为 EVM 兼容和 Substrate 基础项目提供全面的智能合约审计和技术顾问服务。请在 X 上关注我们,以了解最新的行业趋势和见解。

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

0 条评论

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