EIP-7702引入了一种新交易类型,使外部账户(EOA)能够指定指向实施版本的地址,从而将EOA升级为智能合约钱包,提供社交恢复、交易批量处理和交易赞助等功能。这篇文章详细阐述了EIP-7702的实现原理、应用场景及其与ERC-4337的兼容性,并预示了将来对于账户抽象的可能性。
EIP-7702 引入了一种新的交易类型,允许 Externally Owned Account (EOA) 指定一个地址作为其实现的指针。例如,这个地址可以是一个 通用代理 或 最小代理合约,它将调用消息转发到一个可升级的钱包实现。
为了使解释更清晰,有必要区分“委托(delegated)”代码和“委托者(delegator)”账户。因此,本文有时将委托代码的 EOA 称为“智能 EOA”。
EIP-7702 有效地将 EOAs 升级为像 智能合约 (SC) 钱包 一样的功能,为 EOA 用户解锁可编程性和组合性,并启用以下功能:
EIP-7702 与 ERC-4337 的组合性也带来了显著优势。这种组合性使智能 EOA 能够与围绕 ERC-4337 构建的现有 SC 钱包和基础设施无缝集成,从而简化新功能的开发和采用。当用户使用支持 ERC-4337 的智能合约钱包授权一个地址时,EOA 地址可以作为 ERC-4337 中 UserOperation
的 sender
字段。
尽管智能 EOA 通过社交恢复等机制可以解决“你的私钥现在无人知晓”的问题,但它们并没有解决“你的私钥现在被他人知晓”的问题,因为私钥仍然授予对 EOA 的完全授权。像 EIP-7377 这样的提案,能够将 EOAs 迁移到账户抽象钱包中,或者未来的一些提案允许用户在 EIP-7702 后停用(并可能重新启用)私钥权限,将是填补这一空白的必要条件。
与此同时,在缺乏协议级的安全保证时,钱包客户端可以删除其本地存储的“热”私钥,并提示用户在将 EOA 授权为合约钱包后删除任何本地或外部的私钥备份。然而,这样的措施无法完全消除私钥泄露的风险,尤其是在涉及 供应链攻击 的场景中,比如钱包使用的库或钱包客户端本身中的后门。
那么,智能 EOA 相较于 SC 钱包是否提供了更有趣或方便的功能?在我初步的想法中,保留 EOA 的功能提供了几个独特优势:
当然,以上所有这些都只是初步猜测,用户体验的实际影响可能在于不同的创新钱包应用如何利用这些功能来收集来自各种用户群体的有意义反馈和偏好。例如,以太坊的亚文化,如 Cypherpunks、Regens 和 Degens(在 这篇文章 中的分类),可能在钱包设计上有独特的需求和视角。希望在未来我们可以看到更具多样性的用例和应用程序的出现。
接下来,让我们深入到协议本身。
EIP-7702 引入了一种新的交易类型 SET_CODE_TX_TYPE
( 0x04
),其 TransactionPayload
定义为:
[chain_id,nonce,max_priority_fee_per_gas,max_fee_per_gas,gas_limit,destination,value,data,access_list,authorization_list,signature_y_parity,signature_r,signature_s]
其中 authorization_list
定义为:
authorization_list=[[chain_id,address,nonce,y_parity,r,s],…]
authorization_list
中的 address
字段代表被委托代码的地址,而 EOA 的地址可以从payload负载中 ( chain_id
, address
, nonce
) 和签名 ( y_parity
, r
, s
) 中获取(recovered)。这种 EOA 地址和 EIP-7702 交易的 address
解耦,允许另一个 EOA 账户代表原始 EOA 提交授权,从而实现更灵活的委托和赞助交易。
交易收据定义为:
[status,cumulative_transaction_gas_used,logs_bloom,logs]
在深入到代码之前,以下部分强调一些值得注意的功能作为热身。
authorization_list
不能为空authorization_list
不能为空,确保每个 EIP-7702 交易都包含授权实现地址的明确意图。此外,协议验证每个 authorization_list
元组的参数,包括 address
长度和 chain_id
、nonce
、y_parity
、r
和 s
的合理范围。
authorization_list
委托在 authorization_list
的每个元组中,address
字段代表授权地址,而签名者的地址则通过签名和负载推导出。此设计允许 EIP-7702 将 gas 支付的责任从被授权的 EOAs 委托出去,实现广为人知的 赞助交易。例如,Layer 2 sequencer 可以直接集成 EIP-7702 钱包创建接口,或添加 API 收集用户授权并将其与 authorization_list
批量提交。钱包服务提供商也可以帮助没有余额的用户提交交易。
值得注意的是,即使一个批次中的授权失败,其他授权仍然不会受到影响。此设计有助于执行(赞助)批量授权交易。
EIP-7702 引入了一种新机制,在每次成功授权后增加 EOA 的 nonce。nonce 的处理过程如下:
有关代码路径的信息,请参见 Nonce Increment Logic 部分。
这意味着,如果一个交易包含授权列表,并且授权签名者与交易签名者相同,则必须将 tx.nonce
设置为 account.nonce
,而 authorization.nonce
设置为 account.nonce + 1
。如果一个交易包含多个由同一个 EOA 签署的授权(在实际用例中不会发生),每个授权的 nonce 必须顺序增加。总体而言,对于 SDK 来说,这一机制可能会增加对委托交易的初始化复杂性,尤其是在处理所有情况下。
在 EIP-7702 之下,从 EOA 的角度来看,ETH 余额现在不仅可以通过签名交易减少,还可以通过触发合约执行的交易减少。从智能合约的视角看,EOA 可以直接发送交易来更改账户状态。这引入了以下考虑:
用户可以利用 EIP-7702 修改授权地址。如果将 address
字段设置为 0x0000000000000000000000000000000000000000
,则以往的授权将被撤销。这将清除账户的代码并将账户的代码哈希重置为空哈希。
重新委托账户需要谨慎的存储管理,以避免碰撞,这否则可能导致未定义的行为。为了解决账户迁移中的挑战,ERC-7201 根存储布局在独特的插槽中,以避免重新委托时存储位置的冲突。 ERC-7779 (草案) 还提供了一种标准化的 EIP-7702 钱包重新委托过程,具体措施包括:
EIP-7702 采用了 EIP-1559 定义的 gas 费用模型,要求发送方指定 max_priority_fee_per_gas
和 max_fee_per_gas
而不是单一的 gas_price
字段。交易还可以包含 access_list
和 data
等字段,使其保留其他以太坊交易的大部分功能(尽管它不能 携带 blobs)。与 EIP-4844 相似,EIP-7702 强制限制 destination
(在其他类型交易中也称为 to
)字段不能为空,符合限制创建合约的常见做法。
以太坊中的另一个众所周知的禁令涉及禁止与存储相关的指令(例如 EIP-7562)。EIP-7702 并未实施这样的禁令,因为存储指令对 SC 钱包来说是重要的。
更多细节将在下一部分介绍。
在这一部分,我们将深入研究:
代码分析集中在开源库 Geth 上,这是 Client Diversity Dashboard 上列出的主要以太坊客户端之一。EIP-7702 特性的完整 Pull Request 可在 这里 查找。
在进行任何操作之前,我们假设该节点已经激活 EIP-7702,无论是通过硬分叉(从区块高度或时间戳)还是从创世区块。
要发送 EIP-7702 交易,用户首先需要填写 authorization_list
以外的所有非签名字段( SetCodeTx
的定义在这里)。然后,用户在 这里 构建 authorization_list
。对于每个 authorization tuple
,用户首先填写 非签名字段,然后使用 SignAuth 函数进行签名。
用户的 EOA 私钥是签名所必需的。签名涉及对 授权细节 进行哈希,包括魔数 0x05
、链 ID、委托代码地址和 EOA 的当前 nonce。魔数 0x05
也是 EIP-7202 中的一个域分隔符(另一个是 SET_CODE_TX_TYPE
0x04
),确保当不同类型的数据碰巧编码成相同字节表示时,所生成的待签名哈希不会跨域碰撞。关于当前签名域常量的更多讨论可以在 这里 找到。
值得注意的是,将链 ID 设置为 0
允许将授权在支持 EIP-7702 的所有 EVM 兼容链上重放,前提是 nonce 匹配。然而,由于 nonce 必须相同,跨链重用授权在实践中可能具有挑战性。例如,对于具有非零Nonce的 EOAs。
一旦除 交易的签名字段 以外的所有字段都准备好,用户初始化交易( 这里的说明)和一个“ prague signer”(它增加了对 EIP-7702 交易哈希 的支持)。然后,用户使用 SignTx 签署交易,并通过 RLP 编码 通过 MarshalBinary 将其序列化成字节数组。最后,交易的 RLP 字节数组通过 使用 eth_sendRawTransaction
RPC 方法的16进制编码 发送。
当一个节点通过 JSON-RPC 接收到交易时,它进行验证并将其添加到交易池[4],并向其他节点广播。最终,区块提议者尝试将其包含在一个区块中。在包含之前,提议者执行 preCheck,其中包含 EIP-7702 交易的一些附加检查:
在执行交易之前,节点计算 IntrinsicGas,计算访问 authorization_list
的 gas 成本( 详细信息在这里)。如果目标地址之前不存在,则消耗的每个授权元组 25000
gas 成本,定义为 CallNewAccountGas (同样也是 EIP-7702 中的 PER_EMPTY_ACCOUNT_COST
),如果账户已经存在于状态中(即此交易之前已委托),则在应用委托时为每个元组添加 部分退款。
最后,在状态转换过程中,节点应用 authorization_list
中的每个元组( 实现见这里)。该过程包括 验证元组、为现有账户退款 gas、增加 nonce 和处理 授权 或 撤销 的代码修改。重要的是,即使 applyAuthorization 失败(例如由于 validateAuthorization 失败),批次中的其他授权仍然不会受到影响。此设计最大限度降低了批量授权场景中的 拒绝服务 (DoS) 攻击 风险,这在赞助交易中尤其有用。
在 授权验证 期间,节点首先验证 auth.ChainID
是否为 0
或与链 ID 匹配。接下来检查 auth.Nonce
是否未超过最大允许值(每 EIP-2681 规定为 2^64-1
),并 验证签名值并恢复签名者地址。然后触摸的地址被 添加到访问列表,并且节点确保该地址 没有代码或已有委托(即不是合约),并且账户 nonce 匹配提供的auth.Nonce
。
在执行 EVM 调用 之前,节点 将 EIP-7702 地址标记为热地址,遵循 EIP-2929。
EIP-7702 由于包含 authorization_list
引入了一条新的 nonce 增加路径。因此,新增该部分以覆盖 nonce 处理的整体框架。下述为 nonce 处理的详细过程:
authorization_list
中的每个授权元组,验证 auth.Nonce
确保其与签名账户的当前 nonce 匹配( 验证见这里)。在成功验证后,增加与授权关联的 nonce( 增加见这里)。用户可以使用 eth_getTransactionByHash
和 eth_getTransactionReceipt
查询交易状态。EIP-7702 交易的执行路径与其他交易相同。对于 交易负载中的 EIP-7702 字段,节点添加了特殊处理。然而,与其他交易类型相比,在 交易收据 中没有额外的字段( 在 Geth 中对整体收据字段的定义),因此收据无需特殊处理。
上述方法仅确认交易是否已包含在区块中。然而,在授权的情况下,如果授权元组未通过 有效性检查,则它将被跳过。保持 EOA 地址和其委托代码地址在交易被包含后的最新映射的一种方法如下:
eth_getTransactionByHash
获取交易( 代码),并获取 授权列表。对于每个 authorization tuple,尝试 恢复(recovering)授权:eth_getCode
查询恢复地址的代码( 调用示例)。这将返回地址的完整代码( 23
字节),不同于 EXTCODECOPY
仅返回指定符的前两个字节(即 0xef01
),然后通过 ParseDelegation 进行处理,以确定账户是否已委托给代码(第二个返回值)及其委托的代码地址(第一个返回值)。关于指令集更改,在实现中,节点 基于之前的指令集, 增加了 EIP-7702 的指令集修改,并 初始化了一个支持 EIP-7702 的新指令集。此更新的指令集 在检测到硬分叉时在 EVM 解释器中启用。 指令集的具体变化 包括:
EXTCODECOPY
仅返回 0xef01
,通过将地址标识为委托 EOA 地址的前两个字节 [DelegationPrefix](https://github.com/ethereum/go-ethereum/blob/f808d7357ed4076b224a8c6fe47893ce022f9409/core/types/tx_setcode.go#L32-L34)
的 0xef0100
,即 0xef01
。EXTCODESIZE
仅返回 2
,这是 0xef01
的字节长度。EXTCODEHASH
仅计算 0xef01
的 Keccak256 哈希。CALL
、CALLCODE
、DELEGATECALL
和 STATICCALL
将从委托代码地址加载代码并在智能 EOA 的上下文中执行。通过检索 代码哈希 和 代码,在执行这些操作码时实现。无效的委托(例如,没有有效代码或预编译合约地址)将被 忽略并视为没有代码。CALL
、CALLCODE
、DELEGATECALL
、STATICCALL
) 的 gas 调整:这些调整考虑到 EOA 地址与代码地址的访问。Geth 将此逻辑封装到 统一函数 中,并根据 EIP-2929 扣除适当的 gas 成本。在 EIP-7702 之前的 gas 计算见 这里。差异在于 对委托代码地址的额外访问。与智能 EOA 的交互类似于调用智能合约。用户只需将交易的 to
字段(或 EIP-7702 交易的 destination
字段)设置为智能 EOA 地址。这适用于来自外部交易或来自另一个合约的调用。
以下是值得注意的协议实现:1. 在交易 preCheck 中,提议者允许智能 EOA 通过 特殊处理 绕过 EIP-3607,使得 EOA 可以作为 tx.origin
发送交易。对于详细实现,提议者 读取账户的代码 并 使用 ParseDelegation
来识别该地址是智能 EOA 还是合约。
智能 EOA 的代码格式为 0xef0100 || address
(其中 ||
表示连接),确保与现有合约代码没有冲突。该编码利用 EIP-3541,它拒绝以 0xef
字节开头的合约代码。0xef01
前缀确保与 0xef00
(被 EIP-3540 保留)没有冲突,且紧随其后的 0x00
被保留以允许今后可能的 EIP-7702 升级。委托编码和解码逻辑在 此处 实现。
EIP-7702 禁止递归委托(例如,创建潜在的指定者链或循环),以确保协议的简单性。节点仅检索 一层委托。
在通过概念示例浏览完代码后,让我们通过具体示例分析 EIP-7702 的实现和功能。
我们使用 Ithaca 提供的 EXP-0001 示例进行说明。此示例为创建钱包提供了简洁的实现。其工作原理如下:
address(this)
恰好是 EOA 地址)来实现的。构建交易时,EOA 签署授权信息,该信息随后 作为 calldata 的一部分传递。在钱包创建后,用户可以通过签署和执行调用来转移资金。用户使用 WebAuthn 密钥 签署合约调用,并 根据特定的钱包实现提取所需的字段 。参数被准备并 用于调用合约。在该演示中,交易是通过 odyssey_sendTransaction
接口发送的。对于兼容 ERC-4337 的钱包,它可以替代地构建为 UserOperation
并发送到聚合器。
execute
函数。为了增强互操作性和简化 SDK 及钱包开发,可以围绕 multiSend
功能设计一个标准化的 ERC。EXP-0001 演示开启了许多功能可能性。虽然它并未实施为 ERC-4337 兼容,但可以通过用 ERC-4337 兼容合约替换演示的 已部署合约 来轻松实现,例如 Coinbase 的 智能钱包。因此钱包可以无缝继承所有 ERC-4337 特性。
基于前面的示例实现,现在已经可能实现账户恢复。当私钥丢失时,用户只需使用其注册签名密钥从 EOA 账户转移资产。这对于想要保护自己免于丢失私钥的现有 EOA 用户特别有用。在实际使用中,更安全的方法是正确配置社交恢复权限。例如,不允许频繁使用的热签名密钥转移所有资产,而是采用更安全的设置,要求多个监护人签名才能移动余额。
对于新用户,钱包可以帮助简化配置监护人的过程。例如,它们可以提供 一个 2/3 方案,使用:
EIP-7702 通过委托给支持这些功能的合约来启用钱包恢复,利用 零知识证明(ZKP) Zero-Knowledge Proof (ZKP)。ZKP 的一个优势是验证用户信息而不泄露隐私。例如,身份验证可以利用 OpenID 提供商(如 Google 或 Facebook)来签发 JSON Web Tokens (JWTs) 作为 ZKP 的证据,利用已建立的身份验证基础设施。
以下是一个基于 EIP-7702 的 ZK 恢复 示例,由 zklogin 提供。为了更换钱包的签名密钥,用户必须使用新的 WebAuthn 密钥通过 OpenID 提供商的登录流程(在示例中,为 Google)获得 JWT。此 JWT 然后用于 生成证明。最后,证明和来自 JWT 的附加元数据以及新的 WebAuthn 公钥 被提交到合约 以更新签名密钥。
如今,用户经常通过钱包提示窗口授权操作,这在高频率、低价值的支付场景中可能导致疲劳。相比之下,像信用卡这样的传统系统中的“受信任”的基于订阅的支付服务可以减少授权的认知成本。
简化用户操作的一种方式是将不同用途的密钥(例如,签名低权限交易、加密和解密消息[6])与钱包的私钥(具有最高权限)分开。继续以 Ithaca 的 EXP-0002 为例,在创建钱包的过程中,演示程序使用 Web Crypto API 生成签名密钥,并将其存储在 IndexedDB 中。这允许与演示具有相同源的网站通过特定接口访问签名密钥,使前端应用程序能够执行签名操作而无需触发钱包提示。
演示未具体说明签名密钥的后续处理。在实践中,钱包客户端可以为签名密钥分配 生命周期 和 权限 并委托给私钥管理服务。例如,Privy 已在此 演示视频 中演示了如何创建和存储“会话密钥”。
EIP-7702 可以帮助 EOA 用户体验 SC 钱包的功能,例如社交恢复、订阅等。然而,因为它保留了私钥的存在,它不能完全替代 ERC-4337。对于已应用 EIP-7702 的用户,他们如何完全获得 SC 钱包的安全保证?
作者认为,这可以通过兼容性补丁来实现,以支持完全迁移到 SC 钱包,例如 EIP-7377 中提出的迁移交易概念。通过稍作修改,它可以支持将 EIP-7702 账户迁移到 SC 账户。例如,在账户状态中添加一个 deactivated
字段以表示被禁用的 EOA 私钥。如果用户需要撤销被禁用的状态,则需要 SC 钱包的最高权限,例如要求 M-of-N 签名来自监护人。
保留“撤销被禁用状态”的能力的目的是解决通过可升级合约的升级无法完全实现的迁移场景(或合约不可升级)。在这种情况下,需要重新启用私钥的权限,然后再发送另一个 EIP-7702 交易将 EOA 委托给另一个代码地址。
例如,用户可以将其委托代码升级,以彻底迁移到 EVM 对象格式(EOF) 合约,利用 EOF 所支持的新升级方案,并消除传统代理合约的需要。虽然 EOF 允许现有代理合约的传统路径使用 EOF 升级,但删除代理合约可以通过消除通过代理转发调用的开销来降低交易成本。
此外,以太坊和 L2 社区正在积极讨论原生 AA。假设以太坊生态系统将逐渐走向原生 AA 世界,EIP-7702 与这些提议的兼容性如何?
在 L2 中, RIP-7560 的设计意在开创原生 AA 在 L2 的实验和实施,连同相关提案:RIP-7711、RIP-7712 和 RIP-7696。RIP-7560 将 ERC-4337 提供的工具与 EIP-2938 中的原生 AA 设计相结合,引入了一种新的 AA_TX_TYPE
交易类型。与 ERC-4337 相比,它享有原生交易的优势,如消除对额外 RPC 接口的需求,使用合约地址作为 tx.origin
,具有更低的Gas成本(基本 UserOperation
额外Gas开销约为 ~42k,相比之下基本交易约为 ~21k),并受益于协议级审查抵抗机制。
当 RIP-7560 广泛采用时,依赖 ERC-4337 钱包或与 RIP-7560 不兼容的其他钱包的用户可以使用 EIP-7702 更新其委托合约以支持 RIP-7560 的新接口。这是必要的,因为 RIP-7560 引入了与 ERC-4337 的钱包接口相比的变化,例如通过回调函数处理错误,以减少技术债务。使用代理合约的用户可以选择通过升级实现地址来采用 RIP-7560 接口,以确保平滑过渡。
在以太坊上,EIP-7701 基于 RIP-7560 的设计提出了一种原生 AA 机制。关键区别在于利用 EOF 定义入口点函数接口,解决了目前依赖 Solidity 函数选择器作为入口点所导致的技术债务(例如,一个怪异或恶意的钱包可以使用不可读的函数名称创建与钱包接口相同的函数哈希)。通过利用 EOF,用户可以通过 EIP-7702 升级其智能 EOA,以确保与 EIP-7701 兼容,无论是迁移到新的基于 EOF 的合约还是更新其代理合约的实现地址。
正如 这篇博客 中讨论的,钱包可以实施简单的监护人策略,例如 2 选 3 方案。这包括通过 zk-email 验证用户的电子邮件地址、存储在用户设备上的本地密钥(例如,通行证)以及由服务提供商持有的备份密钥。↩︎
任意签名密钥通过如 RIP-7212 和 RIP-7696 等预编译合约在 L2 中得到积极支持,使 AA 钱包能够验证来自各种密钥类型的签名。↩︎
解决这些隐私问题的一种潜在方法是将用户的 SBT 和链上活动分布到多个隐私钱包地址,同时保持对这些资产的全局视角。当需要验证时,可以提交 zk 证明以证明所有权或参与,而无需透露敏感细节。↩︎
虽然 EIP-7702 引入了 EOA nonce 可以增加的新场景,但交易池仍然能够处理 nonce 已更新的地址,通过监控节点上新增的区块。这确保了较低 nonce 的交易会被驱逐。然而,一旦 EOA 将代码委托给其他人,在交易的任何点都可以调用该代码,打破了一个广泛使用的账户余额不变性,以使得通过迭代新块的发送者来使未处理的交易失效:EOA 仅能通过交易发送价值。这要求交易池逻辑相应更新。更多详情见 这里。↩︎
这在端到端加密的消息或电子邮件服务中常见,这些服务集成了 ERC-4361: 使用以太坊登录,例如 MetaMail。↩︎
- 原文链接: hackmd.io/@colinlyguo/Sy...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!