DEFI - ComposableCoW 架构

本文档介绍了 ComposableCoW 的架构设计,旨在提高 CoW Protocol 与 Safe 的互操作性,实现更高效的条件订单处理。

ComposableCoW 架构

以下原则已应用于架构设计中:

  1. 对于 n 阶的创建/替换/删除操作,具有 O(1) 的效率。
  2. 对于 EOA(资产的自我托管,无需创建“容器”合约),条件订单应该表现得与离散订单相同。
  3. 订单是 加粗无状态加粗 的,任何所需的数据都通过 calldata 传递。
  4. 使 CoW 成为 Safe 的一等公民,反之亦然 🐮🔒。

假设

  • CoW 协议强制执行单次使用订单,即任何 GPv2Order 都不能被多次执行。

定义

加粗条件订单加粗:表示 0..n 个离散订单的逻辑结构。

加粗离散订单加粗:提交给 CoW 协议 API 的订单(即 GPv2Order.Data),即 CoW 协议定义的单个 orderUid

为了本文档的目的,如果未指定订单的加粗类型加粗,则应假定为加粗条件订单加粗

使用案例

目前,与 CoW 交互的加粗智能合约加粗需要:

  1. 调用 GPv2Settlement.setPreSignature(orderUid)(API 签名类型为“预签名”);或者
  2. 实现 isValidSignature(bytes32,bytes)(API 签名类型为“eip1271”),其中传递的 bytes32 参数是 GPv2Order.Data 的 EIP-712 摘要。

目前,订单一直在链上产生新的合约,需要处理基本的 retrieve / cancel 功能来恢复资产。Safe 已经为此目的提供了最好的解决方案,所以我们不要重新发明轮子!🛞

此修订后的架构旨在实现的使用案例包括:

  • 自动将 token ABC 兑换为 XYZ,当 ABC 的余额高于定义的阈值时。
  • Good after time ( GAT) 订单(离散订单,以开始时间为条件)。
  • 通过将订单分解为 n x GAT 订单来实现 TWAP。
  • 私有条件订单(追踪止损)
  • Wait4CoW 订单(仅与其他 CoW 交易者匹配订单)
  • 同时执行以上所有操作( n x conditional orders

当前架构

架构分析是从使用 Safe 与 CoW 协议的角度进行的。

所有 CoW 协议的离散订单都经过“签名”。签名方法包括:

  • EIP-712 (gasless)
  • Eth-Sign (gasless)
  • EIP-1271 (gasless)
  • Pre-Sign (tx)
EOA Only
EOA Only
Contract Only
Contract & EOA
GPv2Settlement
EIP-712
Eth-Sign
EIP-1271
Pre-Sign

通过 Safe 进行签名是通过 approvedHashthreshold 签名完成的,如下所示:

delegatecall SigningLib
manual assembly of signatures
Safe
approvedHash - tx
threshold - gasless

因此,当使用 Safe 时:

  1. 每个 离散订单(即 orderUid)必须由 Safe 单独批准/签名。
  2. 从 CoW 协议和 Safe 的角度来看,只有 threshold 类型的 EIP-1271 签名是 gasless 的。

结果是用户体验受到了极大的限制。

ComposableCoW

该合约实现了 ISafeSignatureVerifier,旨在与 ExtensibleFallbackHandler 一起使用 - Safe 的一个新的 FallbackHandlerExtensibleFallbackHandlersafe 提供了第三种 EIP-1271 验证方法 - 它允许将 EIP-712 域委托给自定义合约

因此,ComposableCoW 将处理 GPv2Settlement.domainSeparator() EIP-712 域的所有 EIP-1271 签名。

因此,ComposableCoW 负责:

  1. 每个 ownern 个条件订单的离散订单验证路由。
  2. 从条件订单中查找离散订单(瞭望塔)。

订单数据

每个条件订单在清算时都具有以下属性/数据,具体取决于实现:

  1. handler - 将验证条件订单参数的合约。
  2. salt - 允许同一类型和数据的多个条件订单。
  3. staticData - 条件订单创建的所有 加粗离散加粗 订单都可以使用的数据。
  4. offchainData - 从链下加粗可选地加粗 提供给 加粗离散加粗 订单的数据。

由于所有这些(不包括 offchainData)在创建时都是已知的,因此它们被组合在结构体 ConditionalOrderParams 中:

struct ConditionalOrderParams {
    IConditionalOrder handler;
    bytes32 salt;
    bytes staticData;
}

ConditionalOrderParams 具有以下属性:

  1. H(ConditionalOrderParams) 必须 是唯一的。
  2. 当需要时salt 应该 设置为密码学上安全的随机值,以确保 (1)。
  3. 提供订单保密性(直到从此条件订单中截取的离散订单广播到 CoW 协议 API)。
  4. 所有值在调用订单类型的 verify 之前,都ComposableCoW 验证

offchainInput 具有以下属性:

  1. 允许输入(例如来自链下 oracle 的输入),这些输入在订单创建时是已知的。
  2. ComposableCoW 验证。验证是 handler 的责任。

警告:订单实现必须验证 offchainInput

存储

mapping (address => bytes32) roots; // For Merkle roots (n conditional orders)
mapping (address => mapping (bytes32 => bool)) singleOrders; // Per conditional order (if not in Merkle root)

清算执行路径

CoW 协议订单清算执行路径(假设 safe):

call: isValidSignature
delegatecall: isValidSignature
call: isValidSignature
call: isValidSafeSignature
call: verify
GPv2Settlement
SafeProxy
SafeSingleton : FallbackManager
ExtensibleFallbackHandler : SignatureVerifierMuxer
ComposableCoW
IConditionalOrder

实现 ISafeSignatureVerifier 意味着 ComposableCoW 将实现 isValidSafeSignature

function isValidSafeSignature(
    Safe safe,
    address sender,
    bytes32 _hash,
    bytes32 domainSeparator,
    bytes32, // typeHash
    bytes calldata encodeData,
    bytes calldata payload
) external view override returns (bytes4 magic);
  1. encodeData:在清算期间被验证的订单的 ABI 编码的 GPv2Order.Data
  2. payloadabi.encode(bytes32[] proof, ConditionalOrderParams params, bytes offchainInput)
  3. typeHash 被忽略,因为 CoW 协议只有一个 typeHashGPv2Order.Data)。

清算有效性

以下安全约束由 ComposableCoW 强制执行:

  1. ConditionalOrderParams 必须 获得 owner 授权才能使用。
isValidSafeSignature
valid
invalid
valid
invalid
valid
invalid
Extensible Fallback Handler: SignatureVerifierMuxer
Check Authorisation: MerkleRoot
 Proof & ConditionalOrderParams
IConditionalOrder:verify
Check Authorisation: Single Order
 ConditionalOrderParams
Revert
Return ERC1271 Magic
Merkle Root

叶子: H(ConditionalOrderParams),即 H(handler || salt || data)

属性:

  • 实现了对于添加/删除 n 个条件订单的 O(1) gas 效率。

方法:

调用者将 abi.encode(bytes32[] proof, ConditionalOrderParams params) 作为 payload 参数传递,其中 proof 包含 Merkle Tree 证明。

授权:

如果 proof 断言 节点 H(params) 是 merkle tree roots[owner] 的成员,则订单 O 为有效。

单个订单

属性:

  • 用于启用订单的更简单的方法(更少的工具开销)。
  • Gas 昂贵(每个订单 n x SSTORE)。

方法:

调用者将 abi.encode(bytes32[] proof, ConditionalOrderParams params, bytes offchainInput) 作为 payload 参数传递,其中 proof 是零长度的 bytes32[]

授权:

如果 singleOrders(owner, H(params)) == true,则订单 O 有效。

添加 / 删除订单

owner 使用适用的 setter 方法,具体取决于他们希望如何指定订单。

Merkle Root

owner 调用 setRoot(bytes32 root, Proof calldata proof) setter 方法。

struct Proof {
    uint256 location;
    bytes data;
}
  • root:条件订单的 Merkle Tree(叶子 = H(params))。
  • proof:瞭望塔可能会从中找到证明的位置。

私有: Proof({location: 0, data: bytes("")}) - 没有证明可供瞭望塔使用。

日志: Proof.location = 1 并且 Proof.data = abi.encode(bytes[] order),其中 order = abi.encode(bytes32[] proof, ConditionalOrderParams params)

当设置新的 merkle root 时,会发出 MerkleRootSet(address indexed owner, bytes32 root, Proof proof)

注意: ComposableCoW验证通过 proof 参数传递的证明数据以进行 setRoot。验证/确认这一点是客户端和瞭望塔的责任。

注意: Proof.location 有意未设置为 enum,以便将来可以集成其他证明位置,包括但不限于 Swarm、Waku、IPFS 等。

单个订单

owner 调用相应的 setter 方法:

  • 创建订单:create(ConditionalOrderParams params, bool dispatch)

如果 owner 想要公开订单,则将 dispatch 设置为 true,并且订单创建将导致发出 ConditionalOrderCreated(address indexed owner, ConditionalOrderParams params)

  • 删除订单:remove(bytes32 orderHash)

要删除订单,请从初始的 ConditionalOrderCreated 设置 orderhash = H(params)。不发出任何事件,因为订单已失效(任何试图截取离散订单的瞭望塔都会看到 getTradeableOrder() 将 revert)。

离散订单生成

默认是为条件订单使用 Factory 基本模式,其中基于订单的属性,它能够生成可交易的订单(GPv2Order.Data)。

为此,订单实现了 IConditionalOrderFactory 接口。遵循此模式,开发人员必须确保:

H(IConditionalOrderFactory.getTradeableOrder(owner,sender,params,offchainInput)) == _hash

其中 _hash 是传递到 isValidSignature() 调用中的 _hash

高级条件订单

这些实现了顶级的 IConditionalOrder 接口,该接口仅提供原始的 verify 方法,并且不允许生成订单。

瞭望塔

由于这些订单没有被 CoW 协议 API 自动索引,因此需要某种方法将它们转发给 CoW 以包含在批处理中。这是通过引用 ComposableCoW 发出的事件来完成的:

  • ConditionalOrderCreated(address indexed owner, ConditionalOrderParams params)
  • MerkleRootSet(address index owner, bytes32 root, Proof proof)

加粗发出加粗 上述方法的合约应提供一种方法:

function getTradeableOrderWithSignature(
    address owner,
    bytes32[] proof,
    ConditionalOrder params,
    bytes offchainInput
) external view (GPv2Order.Data memory, bytes memory signature);

ComposableCoW 的上下文中,这将:

  1. 确定 owner 是否是 safe,并为 EIP-1271 signature 提交给 CoW 协议提供 SignatureVerifierMuxer 适当的格式。
  2. 如果不是 safe,则根据 abi.encode(domainSeparator, staticData, offchainData) 格式化 EIP-1271 signature

ComposableCoW 将:

  1. 检查订单是否已授权。
  2. 通过使用 IERC165 检查订单类型是否支持离散订单生成(即 IConditionalOrderFactory)(如果不支持,则 revert,允许瞭望塔修剪无效的受监控条件订单)。
  3. 调用 handler 上的 getTradeableOrder 以获取 GPv2Order.Data
  4. 如上所述生成签名数据。

注意: 取消/删除订单时无需发出这些事件,因为调用 getTradeableOrderWithSignature 将产生一个带有自定义 errorrevert,表明该订单在当前状态下永远无效。

接口

IConditionalOrder

这是条件订单的根级别接口,实现了:

function verify(
    address owner,
    address sender,
    bytes32 hash,
    bytes32 domainSeparator,
    bytes calldata staticInput,
    bytes calldata offchainInput
    GPv2Order.Data calldata order,
) external view;

注意: 如果指定的参数与有效订单不对应,则 verify 方法必须 revert

IConditionalOrderFactory

通过实现 ERC165 和:

function getTradeableOrder(
    address owner,
    address sender,
    bytes calldata staticInput,
    bytes calldata offchainInput
) external view returns (GPv2Order.Data memory);

允许生成离散订单以提交给 CoW 协议。

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

0 条评论

请先 登录 后评论
pmZX_qT2Q1yw59KiiT6TPQ
pmZX_qT2Q1yw59KiiT6TPQ
江湖只有他的大名,没有他的介绍。