同一个 UserOperation 签名,能换个 EntryPoint 或换条链重放吗?
不能。ERC-4337 规范明确要求:为防止跨链重放,或针对多个 EntryPoint 合约版本的重放攻击,UserOperation 的签名必须依赖 chainid 和 EntryPoint 地址。换句话说,一条链上为某个 EntryPoint 生成的签名,搬到另一条链、或搬到同一链上另一个 EntryPoint 地址,都不应被接受。本文只讨论这一绑定要求,不涉及签名算法的具体实现。
规范原文的强制口径
ERC-4337 在描述 UserOperation 与 mempool 时写明:用户把 UserOperation 对象发送到专用的 UserOperation mempool;为防止跨链或针对多个 EntryPoint 合约版本的重放攻击,签名 MUST 依赖 chainid 和 EntryPoint 地址。这是规范层面的强制要求(MUST),不是可选项。原文还提到,EIP-7702 的“authorization tuple”可以随 UserOperation 一并提供,但它不被包含在 UserOperation 结构本身之内。理解“签名绑定什么”时,需要把这一区别分清。
两个绑定值各管什么
chainid 标识签名所处的链。不同链即使合约地址相同、代码相同,chainid 也不同,签名因此不能跨链复用。EntryPoint 地址则标识验证入口:同一链上可能同时存在多个 EntryPoint 合约版本,如果签名只绑链、不绑入口地址,就可能被拿到另一个版本的 EntryPoint 上重放。两者合起来,把签名限定在“这条链上的这个 EntryPoint”。
结构里能看到的线索
UserOperation 在链下是一个包含 sender、nonce、initCode、callData、各类 gas 限额、paymaster 字段和 signature 等字段的结构;传给 EntryPoint 时使用打包版本 PackedUserOperation。EntryPoint 的核心接口是 handleOps(PackedUserOperation[] ops, address payable beneficiary),beneficiary 是收取本次打包所收全部 gas 费用的地址。账户侧需要实现 IAccount 接口,其中 validateUserOp 接收 PackedUserOperation 和 userOpHash。规范要求签名依赖 chainid 与 EntryPoint 地址,具体由 userOpHash 等覆盖方式实现,本文不展开实现细节。
一个说明性的假设
假设某账户在链 A 上为 EntryPoint 地址 E1 签了一个 UserOperation。若有人把同一份签名拿到链 B 提交,chainid 不同,绑定条件不满足;若在链 A 上改用另一个 EntryPoint 地址 E2 提交,入口地址不同,同样不满足。这只是用来说明绑定作用的假设场景,具体拒绝发生在哪一步、以何种错误呈现,取决于实现,本文不展开。
对钱包和账户实现者而言,结论很直接:构造待签名数据时,把 chainid 和 EntryPoint 地址纳入签名覆盖范围,是满足 ERC-4337 防重放要求的必要条件;只绑其中一项,都会留下另一类重放面。