现代DeFi 借贷协议 - Fluid + Vault 是如何构建的

  • mixbytes
  • 发布于 2024-06-16 18:52
  • 阅读 300

Fluid是一个现代多层协议,具有基础层和多个实施不同DeFi机制的二级层。本文详细介绍了Fluid的流动性层以及Vault协议的设计与实现,强调了其使用Uniswap V3类似的价格点,允许流动性操作和风险管理的创新方法。整体架构展示了流动性和借贷操作的高效性,具有独特的保护机制。文章逻辑清晰且内容丰富,适合对DeFi协议开发有深入兴趣的读者。

引言

Fluid是一个现代的多层次协议,底层负责主要功能,次层可以实现各种先进的DeFi机制。Fluid的关键特性在其文档中强调,能够利用来自多个源的流动性,保护协议中资金的突然移动,以及允许低清算处罚、高贷款价值比率和Gas效率的基础协议。

Fluid的基本“流动性层”为用户的抵押-债务位置提供重入保护、市场的速率限制,以及从预言机提供/借入的利率和财务模型管理。次级“协议层”允许基于流动性层实施多个协议。今天,项目的GitHub上有三个协议:

我们将主要集中于Vault协议(在代码中称为Vault),因为文章标题中包含“现代”一词,而第一个(“借贷”)协议是提供ERC-4626股份的“基础”借贷,提供所有基本借贷机制以及流动性层的速率限制特性。“stETH”似乎是一个专用的质押ETH协议,但最有趣的机制是在Vault协议中实现的。由于所有协议使用相同的基础层,我们无法完全避免对其他协议的引用,但将主要集中于Vault。

让我们开始吧。

高级设计

主要流动性层在 liquidity 部分中展示,由两个主要模块组成:

  • adminModule,负责治理行动、设置模型参数、汇率和代币配置
  • userModule,负责基本操作,伴随协议中供应/取款和借款/偿还的操作

底层协议,如Vault或借贷,在实现它们自己的逻辑后,使用流动性层的这些基本操作。例如,Vault利用NFT存储用户的抵押-债务位置,这些位置在价格刻度范围内分布(类似于Uniswap V3和CrvUSD),在所有外部Vault逻辑完成后,将基础操作应用于流动性层(例如 在这里在这里)。

这种设计看起来有点像Euler V2设计(在我们之前的 文章中描述),它在基础层提供一些类型的保护,但同时允许在许多不同的DeFi场景中“封装”这个基础逻辑。

让我们深入一下。

核心

治理和模型管理

首先,让我们关注 adminModule,其中包含治理功能。这些Fluid中的功能允许你:

  • 配置和 收集 协议收入
  • 设置 借入/供应利率,根据当前使用的模型
  • 设置 交换价格和不同代币的利率
  • 其他一些与我们的文章无关的功能

设置交换价格和利率的能力尤为重要。在Fluid中,这些通过_exchangePricesAndConfig[token_] 映射进行管理,每种代币的配置在 这里 中描述。值得注意的是,许多Fluid值,包括配置,保存为256位字段,因此Fluid状态的大小与其他协议相比非常紧凑。

主要操作

Fluid协议,包括Vault,在两个不同的层上运行。基本“流动性”层,位于 userModule 中,包含两个基本功能:_supplyOrWithdraw() 和 _borrowOrPayback()。这些功能与可以在Fluid协议中多个位置找到的通用operate()功能集成(例如 在这里(在借贷中), 在这里(在stETH中),或 在这里(在Vault中))。

这个operate()函数执行所有协议中标准的操作,管理流动性的两个方面:供应和借款。它的目的是多元化的:更新协议的储备,通过执行限制保护市场免受剧烈波动,并作为用户进行的任何操作的“安全包装”。例如,在_borrowOrPayback()函数内部,我们可以找到预先后计算的限制。这确保协议的储备的任何突然变化(可能由外部协议逻辑触发)都会被这些限制所控制。

operate()函数接受经过签名的 supplyAmount_ 和 borrowAmount_ 值,允许利用单个函数执行供应/取款和借款/还款操作。这两个金额以token_单位计量、操作一个单一代币。协议中的所有抵押-债务位置都按照“每代币”存储。每个位置保持使用当前代币的单位限制(无需任何转换)或转换为原始USD值(抵押和债务采用相同的计量单位-USD)。

当用户需要将代币转移到协议时,供应/偿还情况通过用户提供的 liquidityCallback() 处理(此处的重入保护非常重要)。

接下来-从 exchangePricesAndConfig 提取两价格:供应价格和借款价格 在这里

然后,工作流分为两个分支:一个 用于供应/取款, 另一个 用于借款/偿还。在这些操作之后,_totalAmounts[token_] 状态会被更新。操作一个单一代币会导致只更新该特定代币在协议中的余额。

随后,协议更新交换价格、利用率和比例。如果更改很大或最后一次更新被认为过时,则会 更新。有关利用率和价格更新的阈值加载在 这里。对于小的变化,仅更新 supplyExchangePrice 和 borrowExchangePrice( 在这里)。

在最后一步,必须的代币数量会被 发送到 用户。

供应和借款

在“供应/取款”分支的 _supplyOrWithdraw() 函数中,协议支持两种类型的供应:一种是累积利息的,另一种是非利息模型。

这两种供应由两个单独的 分支 进行更新。关键数据结构 _userSupplyData 将用户地址映射到每个供应代币使用的uint256值。该值包含所有相关用户供应信息,包括金额、标志和时间戳,打包为单个uint256值中的位区域。

如上所述,供应者无法提取所有的供应代币。当用户提供代币时,使用两个函数:calcWithdrawalLimitBeforeOperate() 和 calcWithdrawalLimitAfterOperate() 计算新的提取限制,限制用户的最终提取限制。

在 _borrowOrPayback() 函数中,涉及“借款/偿还”方面,计算用户的借贷限制两次:操作之前和之后。用户的借款数据包含在 _userBorrowData 结构体中,该结构体作为uint256值进行打包。

如你所见,流动性层的 userModule 中没有清算。这些可清算头寸的管理由底层协议处理。流动性层仅负责跟踪债务、供应和预言机价格。

现在,让我们更深入地探讨特定协议 - Vault。

Vault协议

Vault协议建立在Fluid流动性层之上。Vault实现了一种高效的清算机制,通过将单个头寸合并为组(刻度)来防止单个头寸的清算,大大降低了在波动市场条件下产生坏债的风险。此外,该协议还纳入了坏债吸收特性,确保清算者的清算不会无利可图。

Vault中用户的抵押/债务位置作为NFT存储,包含在 [positionData](https://github.com/Instadapp/fluid-contracts-public/blob/499e1ab40581fa71e71a934f2820d8385f1e1878/contract...

剩余50%的内容订阅专栏后可查看

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

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