现代DeFi 借贷协议 - Euler V2 是如何构建的

  • mixbytes
  • 发布于 2024-05-22 21:23
  • 阅读 56

本文深入探讨了Euler V2的设计与实现,特别是其模块化借贷生态系统和其核心功能,包括ERC-4626标准的单一资产池、以太坊Vault连接器(EVC)的访问控制、抵押品的管理以及风险管理机制。文章通过详细的代码示例和风险管理模型,展示了Euler V2在去中心化金融(DeFi)领域中的创新与安全性,具有很高的技术价值。

作者: Sergey Boogerwooger, MixBytes的安全研究员

简介

DeFi中有许多新的借贷协议。它们使用户能够对冲风险,同时操作多种资产,在市场上进行短期或长期头寸,并有效利用资金。借贷在传统世界中像银行贷款和存款一样,是金融的基石。但为什么会有如此多不同的解决方案?它们与现有方案有何不同?它们打算如何竞争?

如今,在借贷设计中有许多新的想法和方法:去中心化和无需许可的货币市场、“软性”清算、杠杆与激励策略以及更有效的技术设计。

这系列文章的计划是回顾一些现代借贷协议,深入探讨它们的核心算法和重要代码片段。

让我们从Euler V2开始。

Euler V2高级设计

Euler V2技术设计背后的主要思想是“模块化借贷生态系统”。本质上,它由一系列“金库”构成,每个金库被指定用于存储单一的抵押品或借用单一资产。Euler V2为开发人员提供创建自己金库的能力,仅提供基础认证层、金库访问逻辑和多金库操作。

每个金库是基于ERC-4626的合约,处理单一资产。金库接受用户的资产并铸造/销毁份额。金库的设置使用Euler Vault Kit( WP)。

Euler V2的核心是以太坊金库连接器(EVC)( WP),作为访问控制器。它决定用户是否被允许对金库执行特定操作,管理用户账户、操作员(被授权管理用户资产的账户)并促进多重调用。用户可以启用/禁用不同的金库,利用一些作为抵押存储,另一些用于借用或获取闪电贷,这些操作组合可以非常灵活。此外,每个金库可以“附加”自己的奖励机制,使开发人员能够在其借贷协议中实现各种激励形式。以下是一个示例方案:

这里,三个用户利用不同的金库集,在“仅抵押”金库中提供抵押品,并从连接的金库中借款。

Euler V2并未完全控制金库的内部逻辑,允许开发人员实现自己判断用户债务状况和估算抵押品价值的逻辑。例如,开发人员可能选择使用NFT或其它类型的资产作为专业金库。它们可以创建可升级的、有治理的金库或使其完全不可变。金库的组合可能有显著变化,建议阅读WP中关于不同产品线的介绍 这里

有可能部署恶意金库,以盗取用户资金。因此,用户应仔细检查并信任他们所使用的金库。

[NOTE] 以太坊的最后一次Dencun硬分叉已在大多数情况下弃用了SELFDESTRUCT的使用。这使得攻击者无法部署可变的恶意金库,此硬分叉是对Euler V2及类似项目的安全保障的重要补充。

EVC的另一个重要特征是其执行多重调用的能力,允许临时违反限制但最终导致成功一致的结果(例如闪电贷)。例如,用户可以借取超出允许额度的资金,但在后续调用中,他们可以偿还剩余债务,成功完成一系列操作。

Euler的另一特性是能够为账户分配一个“操作员”(合约或EOA),该操作员可以代表用户执行操作,从而允许在Euler金库周围构建额外的服务。

核心

Euler V2的核心是EthereumVaultConnector.sol(EVC)是管理对金库访问的主要合约。

Euler允许一个ETH地址拥有最多256个不同账户,其中最后8位用于作为当前账户的选择器:

这种设计实现了在同时处理多个金库时,执行各种功能,并授权其他地址(“操作员”)操作不同用户账户的权限,所有这些都可以从单个ETH地址进行控制。例如,它允许设置位掩码来指示当前用户的哪些账户被特定操作员“可控”。

EVC的下一个关键方面涉及对账户金库的启用/禁用。当用户想要添加/移除抵押品时,他们必须使用enableCollateral或disableCollateral。然而,如果存在未偿还债务,后者显然可能会被拒绝。此债务在用户从金库借取资产时产生,借款的第一步是enableController,它授权“借款”金库访问用户的抵押品。控制用户的disableController能力并重新获得他们在其他金库中抵押品的访问权的外部逻辑存在于控制器中,但内部使用由金库创建者实现的checkAccountStatus()函数。

所有在金库中的重要操作如借款、还款、闪电贷等都是严格通过EVC执行的(修饰符callThroughEVC可以在 这里找到)。

金库

Euler V2中的金库只持有一个基础代币,这与其他借贷协议存在显著差异,后者的合约通常持有两个或更多的基础资产(至少一个用于借贷,一个用于放贷)。每个Euler金库的主要入口点是EVault.sol合约(我们已经讨论过一些其功能),该合约拥有与代币、份额操作、借贷、清算和治理相关的众多功能。创建新金库的内部功能是这里

在Euler V2中,跨金库操作是通过份额而不是基础代币进行的。例如,在清算期间,清算者接收的是持有抵押资产的金库中的份额,而不是资产本身。这种设计让跨金库操作可以使用统一的ERC20份额,以相同的精度实现统一算法,以保护份额免受汇率操纵(在文章中有很好的描述)。出于同一目的(即防御外部代币的捐赠),Euler V2金库会通过维护基础代币余额的副本,自动跟踪代币余额,随之增加或减少。当代币进出时,这使得使用重基和“费在转移上”代币变得不可能,但这些代币在借贷协议中仍然存在许多问题。

用户余额跟踪逻辑在BalanceUtils.sol中实现,我们可以找到increaseBalance()和decreaseBalance()函数(以及转账和设置许可)。这些函数在finaliseDeposit()finalizeWithdraw()中使用。

协议费用和金库治理费用的收取在WP中有详细描述,并可以在Governance.sol 这里找到。

预言机

价格预言机是任何借贷协议中最重要的组成部分,因为对预言机的操纵是此类协议面临的最常见攻击向量之一。

Euler V2的金库可以通过实现IPriceOracle接口使用任何外部预言机。

在金库中使用的函数:

/// @notice 单边价格:根据inAmount的基础代币数量,你可以获得多少报价代币,假设没有价格差
function getQuote(uint inAmount, address base, address quote) external view returns (uint outAmount);

以及

/// @notice 双边价格:对于销售/购买inAmount的基础代币,你将获得/花费多少报价代币
function getQuotes(uint inAmount, address base, address quote) external view returns (uint bidOutAmount, uint askOutAmount);

预言机价格的主要功能是计算用户的责任和抵押品价值。每个金库都有一个地址称为unitOfAccount,作为责任和抵押品价值的“基本”资产(如这里)。

Euler V2并不依赖于两个代币之间的静态价格;相反,它更倾向于报价,价格依赖于代币数量。这在这里有很好的描述。此外,Euler V2预言机会公开买入/卖出价格(销售或购买价格),因为在一种情况下,我们需要中间价格(即用于清算),或抵押品估算的买入价格(如上面的示例代码所示)。

风险管理

任何借贷协议中最有趣的部分,当然是风险管理部分:账户健康、清算和坏账。

Euler的账户健康逻辑描述在这里。如果用户有_n_种不同资产_c_i_作为抵押品,并且每种资产都有一个LTV(贷款价值比)因素LTVi,那么Euler计算出风险调整后的价值为

如果用户的责任超过此值,账户可能会被清算。

总体抵押品和责任值在这里中的LiquidityUtils.sol中计算,其中每个用户的抵押品进行了汇总。所有值都以当前金库的unitOfAccount为单位进行衡量。此处是抵押品价值的计算(在最后乘以LTV因子)。

清算的可能性在Liquidation.sol中的此处计算。清算的盈利能力(折扣因子)取决于位置违反的深度(总抵押品与债务的比率在这里)。因此,随着责任随时间增加,折扣因子降低,使得清算对清算者越来越有吸引力。

Euler V2中的清算没有限制,清算者可以偿还用户债务的任何金额。

下一步是“宽恕”和“接受” :) Euler V2禁止导致用户健康状态不佳的操作,并且几乎在每个操作后都会执行健康检查。然而,在清算的情况下,当清算者只能偿还部分债务,从而使违反者的账户处于不健康状态时,将使用特殊的forgiveAccountStatusCheck()函数临时禁用健康检查。此部分代码可以在这里找到。健康检查将在后续操作中恢复,但无论如何,此部分代码仍然存在风险,所有清算操作应谨慎进行。

坏账。对于任何贷款协议而言,最糟糕的情况。在Euler V2中,坏账(表明存在债务但抵押品不足以进行清算)通过社会化处理。这意味着坏账简单地消失,减少了总借款,并将损失“社会化”给所有金库存款人。此过程在清算过程中(如果未完全完成)此处执行。

其他实现细节

Euler V2使用特殊的ERC20代币( DToken.sol)来跟踪用户的债务。该代币不会直接参与责任计算,但对该代币的操作(即在还款期间转移债务)对分析债务、还款金额、清算可能性等离线任务非常方便。当前金库所属的DToken地址是由金库地址确定性计算得出的。

另一个有趣的方面是*BalanceForwarder标志,这为提高/降低金库中的余额提供了钩子。根据WP,这是为了让开发人员处理外部奖励逻辑的能力。这类逻辑的示例可以在reward-streams仓库中找到,我们可以在这里找到余额变化的钩子。

结论

Euler V2使用了一套直观且可靠的代码基础,为开发人员提供了核心层、安全特性和基础借贷/放贷机制。它将产品线的设计委托给开发人员,使他们能够结合各种类型的金库和不同的利率模型。这种灵活性使得能够创建从严格的、不可变的、无许可和安全的“着陆区”到多层的、嵌套的和可升级的实验项目的借贷平台。

这种模块化结构,加上简约的“单一资产”金库和控制多重调用,前景非常可期。让我们看看在这有趣的代码基础上将构建出什么。

下一篇文章中,我们将回顾另一个引人入胜的借贷协议。不要错过它。再见!

  • MixBytes是谁?

MixBytes是一支专家区块链审计员和安全研究员团队,专门提供全面的智能合约审计和EVM兼容及Substrate项目的技术咨询服务。请关注我们的X,以获取最新的行业趋势和洞察。

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

0 条评论

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