现代DEX - Curve StableSwapNG 是如何构建的

  • mixbytes
  • 发布于 2024-11-06 12:40
  • 阅读 267

Curve的StableSwapNG是一个去中心化交易所(DEX)项目,旨在高效交易稳定资产。文章详细介绍了其核心组件、池工厂、流动性池、交易过程、动态费用、流动性管理、流动性测量以及实现细节,强调了其在DeFi中的应用和灵活性。通过使用多维不变曲线,StableSwapNG优化了资产交易,吸引了来自不同协议的流动性提供者。

引言

Curve 的 StableSwapNG 是一个去中心化交易所(DEX)项目,旨在有效交易稳定资产或与相同价值挂钩的资产(例如 ETH 和 stETH)。它鼓励来自不同协议的流动性提供者参与,提高市场流动性,并确保平台用户能够轻松交易目标资产。
StableSwapNG 允许为不同代币部署兑换池,每个池最多可容纳八种不同的代币。该实现采用多维不变曲面,与 Uniswap 中传统的二维不变曲线相比,允许三维、四维甚至更高维度的曲线。
StableSwap 不变性及其相应的自动化市场制造商(AMM)设计在 StableSwap 的 白皮书 和其他文献中有详细描述。为了避免深入涉及兑换背后的复杂数学,此讨论将专注于 StableSwapNG 的实现细节。让我们开始吧。

核心 (Core)

我们将探索 stableswap-ng 仓库,从核心组件开始:池工厂 CurveStableSwapFactoryNG.vy。该合约部署两种主要类型的兑换池:PlainPool 和 MetaPool,以及一个特殊的 Gauge 合约,用于分配额外的奖励。

我们将审查 deploy_plain_pool()deploy_metapool() 函数,这两个函数用于创建这两种主要池类型。“plain pool” 旨在用于“标准”代币兑换,而 “meta pool” 可以兑换其他池的 LP 代币。在一个 meta pool 中,有一个“基础”池,其中 LP 代币是列出的第一个代币。

常见的池部署参数包括代币列表(最多八种)、小数位、类型、利率预言机和调用这些预言机的方法签名。其他关键参数是兑换费用和不变曲线的放大因子。代币类型可以 包括

  • 常规 ERC20 代币
  • 具有利率预言机的代币(如 wstETH)
  • 重基代币(如 stETH)
  • ERC4626 股权代币

这些类型的代币在某些情况下可能需要特殊处理(例如,这里)。正如在 Balancer V3 的 文章 中所见,管理 DEX 中的非标准代币总是一项复杂的工作。

值得强调的关键参数是 _implementation_idx。Curve StableSwapNG 允许部署各种类型的池,这些池必须能够升级其逻辑或应用修复。Factory 合约负责 设置 用于部署新逻辑的 PlainPool、MetaPool、Gauge、Math 和 Views 实现合约的新地址。因此,通过其索引从 self.pool_implementations 和 self.metapool_implementations 中选择特定实现。

工厂的部署过程涉及在 self.pool_data 中“注册”新池,配置其详细信息,并将代币地址添加到 self.markets 映射中。该映射允许识别给定代币对的池。为了搜索促进 coin1 和 coin2 之间的兑换的池,键的定义简单地为 uint256(coin1) XOR uint256(coin2)。使用 XOR 确保无论代币地址的顺序如何,都会生成相同的键。示例可以在 这里 找到。

工厂中的另一个池部署函数是 add_base_pool(),该函数仅可由工厂的管理员访问。该池作为 MetaPool 的基础池。

一个有趣的参数是 _ma_exp_time,该参数定义了池移动平均价格预言机的时间窗口。Curve 允许配置此参数,因为不同的代币集需要来自价格预言机的不同“反应时间”。某些代币,尤其是更不稳定的资产,响应需要更快,从而增加预言机对价格操纵的脆弱性。相反,其他代币可以容纳更大的滑动时间窗口,使价格预言机更能抵抗操纵。我们稍后将再次探讨此参数。

新池的部署是通过 Vyper 的内置函数 create_from_blueprint() 执行的。它接收合约实现地址并使用指定的构造函数参数进行部署。在 StableSwapNG 中,此函数不使用盐参数,这意味着所有部署都是使用 CREATE 操作码执行的(与 Uniswap 不同,Uniswap 中所有池地址都是从代币地址确定派生的)。

在 Curve 的 StableSwapNG 中,没有可配置的兑换/流动性钩子(与 Balancer V3 或 Uniswap v4 不同)。逻辑是固定的,只有池和 Gauge 的实现可以通过治理进行修改。

Plain Pool

我们将从 StableSwapNG 池开始——没有包装代币的“plain”池。它的大多数功能与第二种类型的池,即“meta pools”(CurveStableSwapMetaNG)相似。这部分将在稍后讨论。

部署过程的第一步是 初始化 代币列表、放大因子和预言机时间窗口。

在对所有代币的 循环 中,一个有趣的方面是将预言机地址和方法选择器 打包 成一个 256 位的值。通过将 20 字节地址和 4 字节选择器轻松打包在一起,节省了 gas。

接下来,我们处理 ERC4626 代币,这些代币具有基础资产。与这些代币的操作需要理解规模因子(来自小数位),以便与 ERC4626 以及基础代币正确操作。这些值存储在 call_amount 和 scale_factor 数组 中。它们在 这里 为 ERC4626 代币初始化,随后用于获取存储的费率。

池内的代币转移由两个函数管理:

  • _transfer_in():此函数修改池的 stored_balances[coin_idx],并包含两个逻辑分支:一个遵循传统的 transferFrom() 逻辑,而 另一个 假设“乐观”转移,池假定在调用 transfer_in() 之前,新代币已经转移。
  • transfer_out():此函数直接执行将代币转移到用户的操作——通过 transfer() 发送代币并更新 self.stored_balances。

兑换

交易过程始于以下任一函数:exchange()exchange_received()。两者在使用的 _transfer_in 方法上有所不同(要么是 transferFrom(),要么是上述的“乐观”方法)。值得注意的是,第二个“乐观”变种 不能 与重基代币一起使用,因为池的余额在转账和兑换过程中可能会发生变化。两个函数接受被兑换的代币的索引和一个 _min_dy 参数,该参数设置了获得代币的最低数量,从而允许设置滑点限制。

兑换过程中的下一步在 _exchange() 函数中,通过 获取 各种代币类型的实际余额来进行。通过调用 _balances() 函数,处理重基代币的方法是查询实际的当前 balanceOf(self),而不是依赖于 self.stored_balances[i]。然后 _xp_mem() 通过应用相应的费率来计算实际储备值。

兑换的核心是 计算 _dy,该值表示输出代币的结果数量。最后,使用 _transfer_out() 发送代币。

所有兑换相关的数学操作都发生在 __exchange() 函数中,其中主要池变量 D 表示(标准化余额下)总的代币数。放大参数 amp 与 D 和实际储备一起用于计算池中某个代币 y 的目标储备量(如果添加了 x 代币)。这有助于确定 dy,即要发送给用户的 y 代币数量。为了防止舍入问题,目标 dy 值会 减少 一个单位。这种舍入调整可以保护池免受因用户有利舍入而产生的潜在攻击。

计算出的 dy 值随后用于计算一个 动态 费用。该费用从 dy 中减去,并加到 self.admin_balances[j] 中。通过更新协议储备并维护预言机完成该兑换。

费用

让我们回到费用上。在 Curve 的 StableSwapNG 中,费用是动态的,并且从输出代币中扣除,从而增强池的余额(提高 D,增加 LP 代币的价格)。在不平衡的设置中,当添加或移除流动性时也会收取费用,否则用户可能会简单地使用一种代币添加或移除流动性,而不是执行兑换。正确、按比例添加或移除流动性则不收取费用。

“理想”代币数量的计算基于这样一个理念:如果 D 增加了 x%,每个代币余额也应增加相同的 x%。“理想”目标余额的确定使用 D 的这种增加(示例 见此处),并使用差异来 计算 目标费用。有关费用计算的更多细节可以在 此文档 中找到。

动态费用系数取决于两个代币 ij 之间当前的不平衡(公式和行为详述 见此处)。此外,还有一个特殊的 self.offpeg_fee_multiplier 值,该值在池失去其挂钩时由池的治理进行 设置

添加/移除流动性

add_liquidity() 函数接收所有给定数量的代币,并首先检查 D 是否没有 [减少](https://github.com/curvefi/stableswap-ng/blob/af7685d3f1389ab6a244f9c35c91603b10dcfa48/contracts/main/CurveSt...

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

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

0 条评论

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