ERC-7964: 跨链 EIP-712 签名域
支持使用 chainId 0 进行跨链账户操作的 EIP-712 签名。
Authors | Ernesto García (@ernestognw) |
---|---|
Created | 2025-06-05 |
Discussion Link | https://ethereum-magicians.org/t/universal-cross-chain-signatures-for-account-abstraction/24452 |
Requires | EIP-712, EIP-7803 |
Table of Contents
摘要
本 ERC 扩展了 ERC-7803,通过在 EIP-712 域中为通用签名有效性保留 chainId
0,从而实现可读的跨链账户抽象,遵循与 EIP-7702 中建立的相同模式。它允许账户签署消息,通过单个签名授权跨多个链的操作,从而实现跨链意图、多链 DAO 投票和统一账户管理。
动机
当前的账户抽象解决方案需要每个区块链网络单独的签名。这为跨链操作带来了糟糕的用户体验,例如:
- 跨链意图:希望在多个链上原子性地交易资产的用户
- 多链 DAO 治理:对影响不同网络上的协议实例的提案进行投票
- 统一账户管理:管理部署在多个链上的同一账户
- 跨链社交恢复:跨越多个网络的恢复过程
通过扩展 ERC-7803 的签名域以支持跨链场景,本 ERC 实现了这些用例,同时通过显式的链规范维护了安全性。
规范
本文档中的关键词“必须(MUST)”,“禁止(MUST NOT)”,“需要(REQUIRED)”,“应该(SHALL)”,“不应该(SHALL NOT)”,“推荐(SHOULD)”,“不推荐(SHOULD NOT)”,“可以(MAY)”和“可选(OPTIONAL)”按照 RFC 2119 和 RFC 8174 中的描述进行解释。
跨链域语义
当 ERC-7803 中的 EIP-712 域使用 chainId: 0
时,它必须被解释为“在账户存在的任何链上有效”(即使是反事实的)。
跨链签名验证
验证跨链签名的应用程序必须将 chainId: 0
识别为在账户存在的任何链上有效。对于链上验证,账户应该接受签名有效,而不管每个签名域中的 chainId
如何,并且应该过滤掉在当前链上无效的域。
链特定操作显示
实现跨链签名的应用程序应该验证每个目标链上账户的存在。钱包应该以清晰的、链特定的格式显示签名域及其关联的操作,以帮助用户准确了解将在每个网络上执行的操作。例如,钱包可能会显示一个可滚动的列表,如“Ethereum: Transfer 100 USDC to 0x123…”,“Polygon: Approve 50 MATIC to 0x456…”等。
理由
EIP-712 已成为可读和结构化数据签名的标准。假设 ERC-7803 已经实现,它就成为了一个已经简化了从应用程序到用户的构建块。通过重用相同的机制,signingDomains
和 authMethods
成为构建块,可以相对轻松地融入更广泛的生态系统。
本文档扩展了 ERC-7803,并使用这些构建块,以便在与跨链应用程序交互时,获得更一致且更明智的用户体验。
以账户为中心的方法
以账户为中心的方法代表了用户表达跨链意图的最具互操作性的方式。通过将签名绑定到用户账户而不是特定的链,此设计实现了:
- 通用签名:单个签名可以在多个链上有效,从而减少用户摩擦和交易开销
- 钱包兼容性:标准钱包可以实现此模式,而不会破坏现有功能
- 协议安全:在启用跨链操作的同时,保持与现有协议假设的兼容性
chainId: 0
语义
使用 chainId: 0
利用 EIP-712 现有的 chainId
字段来指示跨链有效性。真实网络从不使用零,使其成为“通用”签名的自然选择。
简单扩展
此 ERC 向 ERC-7803 添加了一个简单的规则:将 chainId: 0
域视为在任何链上都有效。除了检查账户是否存在之外,没有新的编码、没有复杂的消息结构、没有额外的验证规则。
向后兼容性
此 ERC 与 ERC-7803 完全向后兼容。不支持 chainId: 0
的应用程序将安全地拒绝此类签名。
参考实现
如何使用此 ERC 来满足 动机 用例的示例集合。
跨链意图示例
用户想要执行跨链交易:在 Ethereum 上出售 USDC,在 Arbitrum 上接收 ETH:
{
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
],
CrossChainOrder: [
{ name: "originToken", type: "address" },
{ name: "originAmount", type: "uint256" },
{ name: "destinationChainId", type: "uint256" },
{ name: "destinationToken", type: "address" },
{ name: "minDestinationAmount", type: "uint256" },
{ name: "deadline", type: "uint256" }
]
},
primaryType: "CrossChainOrder",
domain: {
name: "CrossChainDEX",
version: "1",
chainId: 0, // 跨链有效性
verifyingContract: "0xUserAccount..." // 用户的账户
},
message: {
originToken: "0xA0b86a33E6776885F5Db...", // USDC
originAmount: "1000000000", // 1000 USDC
destinationChainId: 42161, // Arbitrum
destinationToken: "0x0000000000000000000000000000000000000000", // ETH
minDestinationAmount: "500000000000000000", // 0.5 ETH
deadline: 1704067200
},
signingDomains: [
{
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
]
},
domain: {
name: "EthereumSettler",
chainId: 1, // Ethereum
verifyingContract: "0xEthereumSettler..."
}
},
{
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
]
},
domain: {
name: "ArbitrumSettler",
chainId: 42161, // Arbitrum
verifyingContract: "0xArbitrumSettler..."
}
}
],
authMethods: [
{ "id": "ERC-1271" }
]
}
此签名在 Ethereum 和 Arbitrum 上均有效。Ethereum 清算人可以验证它以托管用户的 USDC,而 Arbitrum 清算人可以验证它以向用户释放 ETH。chainId: 0
域启用了此跨链有效性。
多链治理示例
DAO 成员对影响所有链部署的提案进行投票:
{
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
],
Vote: [
{ name: "proposalId", type: "uint256" },
{ name: "support", type: "bool" }
]
},
primaryType: "Vote",
domain: {
name: "MultiChainDAO",
version: "1",
chainId: 0, // 跨链有效性
verifyingContract: "0xVoterAccount..." // 用户的账户
},
message: {
proposalId: 42,
support: true
},
signingDomains: [
{
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
]
},
domain: {
name: "DAOGovernor",
chainId: 1, // Ethereum
verifyingContract: "0xEthereumDAO..."
}
},
{
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
]
},
domain: {
name: "DAOGovernor",
chainId: 137, // Polygon
verifyingContract: "0xPolygonDAO..."
}
}
],
authMethods: [
{ "id": "ERC-1271" }
]
}
此投票签名可以提交给 Ethereum 和 Polygon 上的 DAO 合约,从而实现协调的多链治理决策。
统一账户管理示例
用户想要使用 ERC-7579 模块向部署在多个链上的多重签名账户添加新的签名者:
{
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
],
AddSigner: [
{ name: "newSigner", type: "bytes" },
{ name: "newThreshold", type: "uint256" },
{ name: "nonce", type: "uint256" }
]
},
primaryType: "AddSigner",
domain: {
name: "MultiChainMultisig",
version: "1",
chainId: 0, // 跨链有效性
verifyingContract: "0x1234567890123456789012345678901234567890" // 相同的账户地址
},
message: {
newSigner: "0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", // ERC-7913 签名者
newThreshold: 3, // 将阈值从 4 分之 2 更新为 5 分之 3
nonce: 42
},
signingDomains: [
{
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
]
},
domain: {
name: "MultiSignerERC7913",
chainId: 1, // Ethereum
verifyingContract: "0x1234567890123456789012345678901234567890"
}
},
{
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
]
},
domain: {
name: "MultiSignerERC7913",
chainId: 137, // Polygon
verifyingContract: "0x1234567890123456789012345678901234567890"
}
},
{
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
]
},
domain: {
name: "MultiSignerERC7913",
chainId: 42161, // Arbitrum
verifyingContract: "0x1234567890123456789012345678901234567890"
}
}
],
authMethods: [
{ "id": "ERC-7913" }
]
}
此签名使多重签名所有者能够同时跨所有链部署添加新的 ERC-7913 签名者并更新阈值。相同的帐户地址 (0x1234...
) 存在于 Ethereum、Polygon 和 Arbitrum 上,并且此单个签名授权在所有三个网络上添加签名者。
跨链社交恢复示例
用户已失去对其帐户的访问权限,并且监护人需要跨多个网络启动恢复:
{
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
],
Recover: [
{ name: "account", type: "address" },
{ name: "salt", type: "bytes32" },
{ name: "mode", type: "bytes32" },
{ name: "executionCalldata", type: "bytes" }
]
},
primaryType: "Recover",
domain: {
name: "CrossChainSocialRecovery",
version: "1",
chainId: 0, // 跨链有效性
verifyingContract: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef" // 丢失的账户地址
},
message: {
account: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef", // 正在恢复的账户
salt: "0x1111111111111111111111111111111111111111111111111111111111111111",
mode: "0x0100000000000000000000000000000000000000000000000000000000000000", // ERC-7579 批量执行
executionCalldata: "0x608060405234801561001057600080fd5b50" // 用于替换签名者的编码调用
},
signingDomains: [
{
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
]
},
domain: {
name: "DelayedSocialRecovery",
chainId: 1, // Ethereum
verifyingContract: "0x1111111111111111111111111111111111111111" // DelayedSocialRecovery 模块
}
},
{
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
]
},
domain: {
name: "DelayedSocialRecovery",
chainId: 137, // Polygon
verifyingContract: "0x2222222222222222222222222222222222222222" // DelayedSocialRecovery 模块
}
},
{
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
]
},
domain: {
name: "DelayedSocialRecovery",
chainId: 42161, // Arbitrum
verifyingContract: "0x3333333333333333333333333333333333333333" // DelayedSocialRecovery 模块
}
}
],
authMethods: [
{ "id": "ERC-7913" }
]
}
此签名使监护人(使用结合了多重签名和延迟执行的 ERC7579DelayedSocialRecovery
模块)能够在所有链上安排恢复操作。该模块将需要:
- 监护人签名:实际签名将包含
abi.encode(bytes[] guardians, bytes[] signatures)
,其中 guardians 是 ERC-7913 格式的签名者,而 signatures 是他们的个人批准 - 计划阶段:一旦 5 分之 3 的监护人签名,恢复就会安排在所有网络上,并延迟 N 天
- 安全窗口:N 天的期限,在此期间可以检测并取消恶意恢复尝试
- 执行阶段:延迟后,任何人都可以执行恢复以替换帐户的签名者
- 跨链一致性:相同的恢复操作同时安排在 Ethereum、Polygon 和 Arbitrum 上
executionCalldata
包含批处理的 ERC-7579 调用,以删除受损的签名者并添加新的恢复签名者,从而确保跨所有目标网络的原子恢复。
安全考虑
跨链重放:此 ERC 有意启用跨链重放。签名域将签名绑定到特定帐户,从而防止不同帐户未经授权的使用。接收签名的每个应用程序都应过滤签名域,仅包含与其链相关的签名域,并维护其自身的不可重放方案。
帐户验证:应用程序应验证签名帐户是否存在于使用签名的每个链上。不应接受在 Ethereum 上存在但不在 Polygon 上存在的帐户在 Polygon 上的签名。对于尚未部署的反事实帐户,应用程序应遵循 ERC-6492 来验证签名。
代码和状态差异:请注意,在同一地址,跨链的合约代码和状态可能不同。例如,由于代码差异、状态分歧或链特定逻辑,在一条链上通过 isValidSignature()
的签名可能在另一条链上失败。
原子性:跨链签名不能保证跨所有链的原子执行。签名可能在某些链上部分执行,而在其他链上变得不可执行。这可能会导致用户的资金处于待处理状态,无法实现其意图。开发人员应实施机制,以确保在部分执行的情况下可以恢复。考虑使用 ERC-7786 网关来路由消息和管理跨链状态。
签名过期:未在某些链上执行的签名可能会无限期地保持可执行状态。协议必须实施本机过期或失效机制,以防止突然使用悬空签名。对于具有 chainId: 0
域的签名,这尤其重要,因为它们在帐户存在的所有链上都保持有效。
版权
版权及相关权利通过 CC0 放弃。
Citation
Please cite this document as:
Ernesto García (@ernestognw), "ERC-7964: 跨链 EIP-712 签名域 [DRAFT]," Ethereum Improvement Proposals, no. 7964, June 2025. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7964.