现代 DEX: Cow 协议 - 是如何构建的

CoW协议在现代去中心化交易所(DEX)中的应用, 介绍了其拍卖机制、订单求解和解决方案评分的流程。

介绍

CoW Protocol(以及基于它构建的 CoW Swap)属于 DEX 的“求解者(solvers)”类别。

从概念上讲,求解者代表了 CEX 和 DEX 之间的中间地带,结合了类似 CEX 的订单簿,但将订单匹配外包给独立竞争实体,同时在链上完成交易,类似于 DEX。

CoW Protocol 不仅支持简单订单,还支持可编程订单,这些订单可以在保持相同工作流程的同时,加入额外逻辑。这使得交易者能够开发灵活的交易策略,求解者提供高度响应的执行层,而不受链上限制。此外,CoW Swap 的设计能够避免与 MEV 相关的风险,并提供非常有吸引力的滑点限制。 CoW Protocol 中的求解者可以接触到用户的交易,这可能导致恶意行为,通过偷取费用或重排序来利用交易。因此,CoW Protocol 只支持经过批准的求解者列表,要求每个求解者都要支付一笔大额保证金,如果发现任何不当行为,CoW DAO 可以削减这笔保证金。为了鼓励良好行为,CoW Protocol 通过 COW 代币奖励求解者,激励他们为用户的交易寻找最佳解决方案。 这是一个无疑很有趣的项目,接下来让我们深入了解它是如何构建的!

高层设计

CoW Swap 的高层交易流程如下:用户签署“意图”以交换特定数量的代币,并将其添加到链外订单簿。然后,求解者处理这些订单,寻求最大盈余的交易组合,并在拍卖中发布他们的“批次”以选择最佳方案。最佳批次随后提交到链上智能合约中,结算此“最佳”批次中的所有交易。

这种用户订单的链外匹配和一次性交易结算避免了向流动性提供者直接支付费用,并防止了与交易订单相关的 MEV 操作。此外,求解者可以利用他们的流动性来“支持”他们的批次,从而可能为某些交换提供更好的定价。另一个重要的特性是用户可以在不支付原生交易费用的情况下进行交易,因为他们不需要直接与区块链互动。求解者可以改为收集用户提供的代币中的原生代币费用。

用户单独交易的链上结算效率低下,因为每笔交易都需要支付原生交易费用。为了解决这一问题,CoW Swap 采用“批次(batch)”结算,一次处理多笔交易。这种批次是必要的,因为即使有许多不同的订单,也不常见“理想”的确切交换数量。例如,如果用户想买 100 USDT,求解者可能部分使用另一用户出售的 200 USDT 的订单,或者组合两个订单卖出 30 + 70 USDT,或者通过第三种代币进行中间交易,甚至涉及 3 个以上用户的订单以完成复杂的“轮次(round)”交换。这些情况在 这里 中有详细说明。解决这种交换的真实案例可以在 这里 找到。

在 CoW Protocol 中,使这些批次有效的一个关键概念是“统一清算价格”。同一批次中的所有交易对于相同的 token1/token2 对都使用这个相同的清算价格;否则,解决和证明最佳批次的过程将无法有效进行。在某些情况下,这一方面甚至可以改善交易。例如,当批次中特定订单的统一清算价格优于“波动”价格时,整个订单组将变得更具盈利性。我们将在本文中多次重温这一概念。

在 CoW Protocol 中,订单可以有所不同并实现不同类型的逻辑,例如:

  • 简单订单(数量 + 价格)
  • 限价订单(数量 + 价格 + 到期日期),可以持有直到达到目标价格
  • TWAP 订单 - 一笔大的订单分解成多个小的限价订单,以允许顺序执行并保持每个部分的滑点容差更紧
  • 程序化(Programmatic)订单 - 最强大的一种,允许通过检查链上条件(如价格、阈值和时间)来实施任何逻辑
  • Milkman 订单 - 在交换时可由外部预言机给出的价格执行
  • CoW Hooks - 在执行前后允许订单执行动作的钩子,例如解押/质押资产或签署代币授权

这些订单类型在文档的 这一部分 中有更详细的说明。上述所有类型使 CoW Protocol 具备显著的灵活性,能够使交易者实施多样化的策略。

处理订单批次的求解者必须竞争以提供最佳解决方案。为了确定最佳解决方案,使用一个最大化函数,如 这里 所述。这个函数处理订单集合,按顺序接受“输入/输出”代币的数量(x−y)、交换价格 π,并减去订单费用。为了在不同代币之间标准化这一度量,函数的非负结果以“公共货币单位”表示(例如,以 ETH 表示),其价格由预言机确定。每个求解者提出他们的解决方案,该解决方案的 质量(quality) 定义为:

img

这里,U(o) 是每个订单的 盈余 函数,f(o) 是每个订单的 费用p 是费用单价(确保整个质量结果以“公共货币单位”进行度量)。

在选择最佳求解者后,奖励他们至关重要,以激励他们不仅赢得拍卖,还为用户寻找最佳解决方案。获胜求解者的奖励表示为:

img

其中,observedQuality 是所呈现“最佳”解决方案的质量(在结算时观察),referenceQuality 是第二最佳解决方案的质量,cap() 函数使用预定义的上下限来限制支付(cl, cu) = (0.010, 0.012) ETH。奖励逻辑在 这里 中有详细说明,提到在某些情况下(当最佳和第二最佳解决方案之间的差异很大时),求解者可能会呈现“少报质量”,但这种行为需要求解者付出相当大的努力,因此在当前方案下是可接受的。该方案还考虑了在求解者通过外部 AMM 交换他们的流动性时可能发生的滑点。这一点也在 这里 中进行了描述。

CoW AMM

CoW Protocol 中的另一个关键组件是 CoW AMM。为了满足订单,求解者应使用外部 AMM(如 Uniswap 或 Balancer)进行交换。然而,这种交换容易受到 MEV 和套利的影响,而保持用户盈余对求解者来说至关重要。此外,前面提到的“统一清算价格”适用于相同代币对的整个订单批次,促进最佳订单批次解决方案的形成。因此,CoW AMM 被设计为支持交易批次,而不是以统一价格执行的单次交换。讨论这一 AMM 设计的论文是

这里

CoW AMM 仓库(与 Balancer 合作开发)在

这里

。我们不会深入探讨 CoW AMM 的实现,但与 CoW 协议的主要集成点包括:

拥有这样的“提交” AMM 使得求解者在许多情况下能够在 CoW AMM 中结算交易,而不是使用 Uniswap、Balancer 或 0x 交换池。这种方法简化了批次的统一价格实现,促进了所有描述的方案,其中用户订单被部分填充或组合,以为用户提供最佳的盈余,同时提供防止抢跑的保护。

现在,让我们继续 CoW 协议的实现。

核心

CoW 协议(前称 Gnosis 协议)的代码库可以在

合约仓库 找到。 我们从 GPv2Order.Data 结构体 开始,该结构体保存订单数据,包括:

  • 被交换的代币和接收者的地址和金额
  • uint32 订单过期时间。
  • 额外的 bytes32 appData 用于与订单交互的外部应用。该字段包含一个 IPFS 哈希,指向包含元数据的 JSON,其中可以包括推荐地址、外部 ID 和其他选项。
  • 订单的费用 金额
  • bool partiallyFillable 标志,指示订单是否可以部分填充。
  • bytes32 kind 订单类型,这是字符串“buy”或“sell”的 keccak 哈希。这允许与 EIP-712 兼容的钱包为该字段显示描述性字符串。
  • bytes32 values(卖/买)TokenBalance,指示买/卖代币余额的“来源”:直接 用户的 ERC20 余额,批准 用户的 Vault(将在下面描述),或 内部 Vault 本身的余额。哈希的使用方式与订单类型类似。

接下来,我们讨论 CoW 协议的关键核心合约,该合约处理用户的签名订单,使其可供求解者使用。该合约是 GPv2Settlement.sol。它包含三个额外的合约地址:

  • Authenticator - 负责验证求解者(只有白名单中的求解者可以与协议交互)。
  • Vault - 一个 Balancer V2 Vault 合约。它通过持有用户的代币来促进 Balancer V2 交换,并允许 CoW 协议使用 Vault 余额在 Balancer V2 池中进行高效的交换。
  • VaultRelayer - 直接使用 Balancer V2 Vault 与 GPv2Settlement 是不安全的,因为从 Vault 到 Settlement 的批准允许恶意求解者从 Vault 中抽走用户的资金。因此,需要一个额外的中继器来管理必要的批准,以防止未经授权的抽取。

一个重要的组成部分是 filledAmount

,它通过存储每个 UID 的“已填充”金额来记录订单的履行状态。“完全填充”金额表示订单已完成或

已取消

订单结算

我们现在转向 CoW 协议的最终链上操作,将链下方面留给后续文章部分。最终解决方案结算(来自 CoW 后端的一批最佳交易)由

settle() 函数执行,该函数包括:

  • 执行初始外部交互(“结算前”)。
  • 计算和验证所有订单的目标“进/出”金额。
  • 从账户转移“进”金额。
  • 在“结算期间”执行“代币进/代币出”之间的中间交互。
  • 将“出”代币转移到账户。
  • 执行最终交互(“结算后”)。

我们将探讨这些程序,从通过

computeTradeExecutions() 计算交易执行开始。该函数迭代调用 computeTradeExecution()

对每笔交易进行验证过期时间、买/卖价格,并检查订单是否超额填充。如果有效,它将返回所需的“进/出”金额。

CoW 协议与 Balancer V2 集成,利用其金库来管理代币余额。此集成可以用涉及内部用户和求解者在 Balancer V2 金库中的余额的操作替代外部转账,从而消除额外的批准并利用 Balancer V2 流动性来实现订单履行。因此,CoW 协议中的代币操作可以涉及用户和求解者的直接 ERC20 转账或与 Balancer V2 金库的交互。

“in” 转账由 transferFromAccounts 在 GPv2Transfer.sol 中执行,提供两种处理代币余额的方法:直接使用 ERC20 的 transferFrom()

或为单个接收者组装操作数组并将其传递给 Balancer V2 金库。可以在 这里 探索 Balancer 金库中的代币操作,突出不同类型的内部余额操作。

“out” 转账在 settle() 函数中使用 transferToAccounts(),其功能类似,但允许直接进行金库操作而无需中继控制。直接的 ETH 或 ERC20 转账会发送所需金额,而对于金库操作,则准备并执行一组操作。

接下来,我们讨论在订单结算前、期间和后执行的 executeInteractions()。GPv2VaultRelayer

处理用户的授权,使交互变得风险较高。为减轻此风险,外部操作以安全检查开始,拒绝与 GPv2VaultRelayer 的 交互。执行本身涉及对外部合约的简单调用,成功的返回状态确保操作成功(请记住,外部调用的回退不会传播给调用者)。

GPv2Settlement 合约还提供了 swap()

函数,用于在 Balancer 池中进行直接交换。这会创建一个“就地”交换订单,并调用

GPv2VaultRelayer 的 batchSwapWithFee(),帮助求解者获取所需的流动性以满足用户订单。

订单下单

如前所述,用户的交易被发送到一个离线 API,使其可供求解者进行拍卖。其核心后端在 CoW Protocol Services 仓库 中。这里我们仅覆盖一些部分以便更好地理解。

与订单簿相关的 CoW Protocol Services API 部分在 api.rs 或在 文档 中。

首先,订单的发布,概述在 post_order.rs,包括几个 验证,例如用户签名验证和余额检查。订单取消也 需要 用户签名以防止未经授权的取消。

一旦验证通过,订单将 添加 到数据库。CoW 使用 PostgreSQL,其 SQL 模式及其更新可以在 这里 找到。

与订单状态、拍卖信息等相关的其他领域不在本文的范围内,因此我们将继续讨论求解者的方面。

求解者

在当前批次拍卖中工作的求解者接收一组订单,并应提供最佳质量的解决方案(请参见此 链接)。求解者的示例代码在 solver crate 中提供。

让我们检查示例求解者,它处理多个订单,呈现在 multi_order_solver.rs 中。这里我们看到函数 solve()。它启动一个 循环添加 额外的上下文到订单(例如,Uniswap 上的可用储备),并尝试 找到 一个有效的解决方案。如果未找到解决方案,它会 移除 “较差”的订单并重试。

然后,求解者 选择 最佳解决方案,通过预计算交换的结果,包括费用,并返回最终执行计划。

该执行计划包括给予授权、在不同 DEX 中的交换顺序以产生最佳结果以及其他操作。Uniswap V2/V30xBalancer V2 的执行计划示例已提供。求解者发送的解决方案示例可以在此 页面 找到(检查 /solve 请求)。

接下来是拍卖本身,在 AuctionProcessor 中实现。拍卖实体 包括 此拍卖有效的区块、最后结算的区块、一组订单和一组使用代币的参考价格。

首先,让我们关注使用 比较器 的订单 优先级,基于价格、创建时间和订单所有者(求解者的订单被优先考虑,以便他们提供更好的解决方案)。在同一过程中,额外的 CoW AMM 订单被 注入(cow_amm_order 的创建可以在 这里 检查)。此外,订单会被 过滤,以确保有足够的代币数量来执行交易。

接下来是结算的评分,具体实现见这里 ,并遵循在撰写本文时描述的 CIP38 中的规则。主要的变化是将 gas 成本排除在解决方案评分之外,去除了与解决方案有效性无直接关联的复杂 gas 相关部分。该评分计算计划金额与实际金额之间的差异(见这里这里)。

接下来是竞争 。传入项是异步收集的,然后评分被应用到每个呈现的解决方案上。然后选择最佳解决方案进行选择 。一个重要的部分是对每个新区块的模拟获胜解决方案,直到截止日期,以确保在提交到区块链之前其正常工作。该模拟在这里执行。

实现细节

让我们强调一些重要的代码方面。

CoW Protocol 的大部分功能建立在链下签名之上,要求支持多种签名方案。此代码可能对你的项目有用,因此值得检查该模块中的不同签名恢复函数。

CoW Protocol 中的访问控制非常简单,并在这里实现。主要有两个角色:所有者和管理者,管理者负责管理求解者列表。

外部交互 ,在结算中的 executeInteractions() 中执行,使用汇编语言以避免不必要的返回数据复制,这些数据未被协议使用。另一个外部交互的汇编使用可以在 safeTransfer()safeTransferFrom()的实现中看到。

CoW AMM 使用 TSTORE/TLOAD 指令进行提交锁定。我们建议在需要在单个交易中进行持久存储的任务中使用这种相对较新的方法,而不是昂贵的存储。

结论

基于 CoW Protocol 构建的 CoW Swap 是 DeFi 领域的一个重要项目,充分展示了“求解者”方法在 DeFi 交换中的应用。CoW Swap 的一个显著特点是其对用户和求解者的“双赢”策略:用户的盈余越大,求解者的盈余也越大。虽然它类似于中心化交易所的传统订单簿,但它带来了去中心化,允许任何人参与订单匹配。

CoW Swap 设计的关键点:

  • 预签名的用户订单在链下进行。
  • 用户订单包参与求解者之间的竞争,以寻找交易包的最佳解决方案。
  • 最终的“最佳”交易结算在链上执行,目标金额直接转移给用户。
  • 同一结算中的所有交易与特定代币对以相同的统一价格进行。
  • 交易可以涉及多个外部 DEX,如 Uniswap V2/V3、Balancer V2、0x、CoW AMM。
  • CoW Swap 可以使用其自己的 AMM,具有“提交批次”功能,避免前置交易和 MEV。
  • 求解者由 CoW DAO 选择,提供安全保证金,若行为不当可被削减。

CoW Swap 非常适合缺乏流动性的交易者,他们不想维护自己的交易结算基础设施,面临 MEV 问题,并希望专注于寻找最有利可图的交换策略。

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

我是 AI 翻译官,为大家转译优秀英文文章,如有翻译不通的地方,在这里修改,还请包涵~

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

0 条评论

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