现代 DEX - Fluid 是如何构建的

  • mixbytes
  • 发布于 2024-11-22 20:12
  • 阅读 308

本文详细介绍了Fluid DEX协议的设计和功能,特别是其如何利用流动性层来支持去中心化交易所(DEX)与借贷的结合。文章深入探讨了智能抵押品、智能债务的概念以及流动性提供的动态机制,同时分析了其代码实现和复杂的数学模型。Fluid DEX的特点包括动态的价格变化、流动性合约的优化以及法国LEND-Dex的借贷机制,显示出在DeFi领域的创新潜力。

引言

我们之前回顾了一个基于 Fluid 项目的流动性层构建的协议,称为 Fluid Vault 贷款协议。Fluid DEX 是另一个利用相同基础层的协议,展示了 Fluid 在开发 DeFi 项目时的多层次方法。Fluid DEX 的主要特点是能够使用贷款层的抵押/债务资产为 DEX 中的兑换提供流动性。这使得可以利用兑换费用来增强供应并减少债务。为了实现这些目标,Fluid DEX 采用了“智能债务”和“智能抵押”概念,这些概念是针对资产对而非单一资产工作的。高级概述可以在 这里 找到。

如前所述,Fluid 的基础流动性层提供了记账、重入保护、市场限速和其他基础机制,用于支持底层协议。Fluid DEX 作为第二个“协议层”,使用基础流动性层原语“结算”其资产。我们已经看到,跟踪用户债务/供应的机制可以在 DEX 中用来支持多次调用(例如:Uniswap V4Balancer V3),允许用户通过不同的池执行多个操作,进行兑换,和在单个多次调用中管理流动性。在这些操作中,协议只是跟踪所有被使用代币的累计出入债务,仅允许在多次调用结束时提供所有所需代币,组合所有操作。这种方法显著降低了复杂交易操作的 gas 成本并增强了协议的灵活性。

Fluid DEX 采用类似的方法;然而,基础的抵押/债务层更加复杂,并充当“会计师”,而第二个 DEX 层则作为“操作员”。

让我们来考察一下这个协议的技术设计。

高级设计

我们将跳过一些与 Fluid DEX 的基础流动性层相关的部分,因为在之前关于 Fluid Vault 的文章中已经讨论过。Fluid DEX 的核心机制是“DEX-on-lending”(其中“贷款”是在流动性层实现的,DEX 则在“协议”层上实现)。在这种设置中,单个 Fluid DEX 实例充当与贷款平台接口的唯一贷方/借方。在 Fluid DEX 中的兑换操作促进用户资产在流动性层中的结算,结合存款/取款/借贷/偿还功能来管理代币的“出入”操作。贷款协议的流动性提供者同时也是 DEX 的流动性提供者,而 DEX 的兑换则对抵押/债务资产分配进行再平衡。

作为贷款平台,Fluid DEX 利用“智能抵押”和“智能债务”,这意味着代币对可以作为抵押或债务,而不是单个代币,例如 wstETH-ETH 或 WBTC-cbBTC。因此,用户提供或借贷代币对。即便用户使用智能债务 USDT/USDC 借入 100 USDT,债务被视为持有 50 USDT/50 USDC 的头寸。这种分配可以通过涉及 USDT 或 USDC 的 DEX 交易进行更改。每次用户使用 Fluid DEX 兑换资产时,“智能”贷款供应/借贷头寸中的代币分配会相应调整。从兑换中获得的兑换费用会改变抵押或债务余额,或者增加供应 APR 或减少借款利率。这是 Fluid DEX 的主要概念(高层次的说明可以在 这里 找到)。

为了管理智能抵押和债务,Fluid DEX 中的兑换操作采用两个镜像池进行执行:一个是“供应代币1/借贷代币2”,另一个是“供应代币2/借贷代币1”。兑换过程包括“供应(抵押)& 还款(债务)”的“入”代币操作,和“提取(抵押)& 借贷(债务)”的“出”代币操作,这两个池在基础流动性层上有如下所示:

因此,Fluid 中每个独立的“dex”在流动性层端有两个底层的贷款池,而这个“dex”作为这两个贷款池的用户。在这个框架中,DEX 层根据类似 Uniswap V2 的不变量计算供应/借贷操作的金额,并在池之间对资产进行再平衡,以保持 token1->token2 和 token2->token1 的价格一致。

让我们更深入地探讨这段代码。

核心

Fluid DEX 的代码库与 Fluid Vault 相同:https://github.com/Instadapp/fluid-contracts-public/tree/main/contracts,DEX 协议代码位于 protocols/dex 目录下。

主要合约 main.sol 的 构造函数 包含设置专用合约的地址:

  • colOperations - 管理与抵押的“存款/提取”操作。
  • debtOperations - 管理与债务的“借款/偿还”操作。
  • perfectOperationsAndSwapOut - 处理“完美”的存款/提取/借款/偿还操作,以股份而非代币数量进行操作(保持池平衡)。此外,该合约管理“SwapOut”逻辑。
  • shift - 处理中心价格、阈值和区间的调整。
  • admin - 管理功能。

正如前面提到的,Fluid DEX 是一个“DEX-on-lending”,包括同时作为流动性提供的“贷款”操作(存款、提取、借款、偿还)。这就是为什么在“DEX”协议中也包含传统贷款操作。代码分为三个部分:“抵押”、“债务”和“完美”,将相似操作分组。Fluid DEX 中的抵押和债务操作在两个贷款池中使用再平衡,而“完美”操作无需要再平衡,因此被单独分隔为独立模块。

让我们继续讨论兑换。

兑换

Fluid DEX 的核心功能是 main.sol 中的 _swapIn() 和 perfectOperationsAndSwapOut.sol 中的 _swapOut(),它们是该协议中最复杂的功能。我们从 _swapIn() 开始。

Fluid DEX 限制对兑换价格变化超过 5% 的操作(这是另一个“流动”部分),在兑换操作的最后一个部分(在 _updateOracle() 函数中,我们稍后将讨论)执行 _priceDiffCheck()

Fluid DEX 的价格模型也是“流动”的,因为所有价格变动(甚至是区间和阈值的治理变更)都是根据先前价格的改变进行计算并逐渐执行的。当范围限制被达到时,价格值和范围开始连续地向新值移动。这要求跟踪以前的价格、时间的转移、价格转移的状态和其他变量,以控制池的“动态”行为。含有这些数据的 dex 状态被存储在两个主要变量中:

  • dexVariables:这里关注的是 两个 池的前两次兑换价格和它们之间的时间 差异,中心 价格(将在下面说明)和最后一次交互的时间。
  • dexVariables2:包含 标志(智能抵押/债务启用)、关于 费用 的信息,以及一个包含百分比的 ,确定围绕中心价格的范围(类似于集中流动性设置中的当前区间的上下价格范围)。另一个重要参数是转移的 时间,确定价格移动的速率(将在下面讨论)。下一个 的参数与中心价格的限制相关(可以外部获取、具有最大/最小限制、受到利用率限制等)。另一个显著的标志是 暂停 标志,它禁用所有“失衡”的操作;只能执行“完美”操作(那些不会改变池中代币的相对分配的操作)。

兑换过程参数 存储 在内存中的 SwapInMemory 结构中。

兑换过程中的第一站是 pex_ 结构,它保存协议的兑换价格。这些价格由 _getPricesAndExchangePrices() 函数计算,是 Fluid DEX 兑换的真正“核心”(稍后将讨论)。目前,需要注意的是,供应/借贷代币1/代币2 具有 分开 的价格。

正如先前所提到的,Fluid DEX 中的操作涉及 两个 兑换:在“抵押”和“债务”池中。因此,下一步是为兑换的两个部分准备储备。第 一部分 用于抵押,而第 二部分 用于债务(“虚拟”储备也将在下文中讨论)。

接下来的 部分 处理池中操作数量的限制。我们检查“入”转换的数量是否不会显著影响池的储备和价格。兑换结束时会执行 _priceDiffCheck(),但 Fluid 支持提前进行此检查。

然后进入计算“入”代币金额及其在池中的分配的部分(在一个池中,我们进行“存款”,在另一个池中进行“偿还”)。我们在 _swapRoutingIn() 函数中计算兑换数量,接受“入”数量 t 以及初始的、抵押和债务的“虚拟”储备。该函数的结果为系统方程提供解,同时确定兑换的哪一部分进入抵押、债务或两个池。这个结果形成这 个分支,指示多少数量链入“存款”,多少数量链入“偿还”。

接下来,我们需要计算“出”数量,以便在一个池中“提取”和在另一个池中“借款”。此外,我们需要检查这些所需的数量是否可用。这在“_amountOutCol”和“_amountOutDebt”部分中完成。

接下来,我们决定使用哪个池来确定兑换价格:抵押还是 债务。我们选择拥有较大兑换数量的作为价格来源,但仍需记住,在兑换结束时,给定资产在两个池中的最终价格将是相同的。

经过 转换 代币余额为正常数量后,并 设置 回调数据(如果代币通过回调进行传输),有两个与基础流动性层的操作。Fluid 的流动性层(所有 Fluid 协议共享)通过一个 operate() 函数处理所有操作:存款/提取/借款/偿还,由两个签名参数 supplyAmount_ 和 borrowAmount_ 决定(这些参数的负值会导致反向操作)。第一个操作是:

LIQUIDITY.operate(..., +supply_amount, -payback_amount, ...);

而第二个是:

LIQUIDITY.operate(..., -withdraw_amount, +borrowAmount, ...);

这些操作将所有“入”代币用于供应抵押和偿还债务,同时“出”代币则用于提取抵押和借款在协议的流动性(“贷款”)层之上。

接下来调用一个附加的钩子,如果抵押或债务池需要清算,则可以停止兑换。我们在贷款一侧有一个 Fluid DEX 的贷款头寸,这个头寸可能变得“不健康”,需要清算。在这种情况下,任何兑换在清算发生之前都应被中断。“健康”状态是通过该钩子进行检查的,其接口和说明可以在 这里 找到。然而,DEX 的组合、智能债务/抵押代币对的慎重选择,以及根据外部市场价格调整这些池中的资产的再平衡,使得这种情况不太可能发生。

兑换的下一部分包括 检查 流动性层中的利用率(total_debt/total_collateral 比)。函数 _utilizationVerify() 检查最终利用率是否 不超过 流动层中的限制(在流动性层的 operate() 函数中的利用率使用示例见 [这里](https://github.com/Instadapp/flu...

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

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

0 条评论

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