CodeBucks logo
WangDou
中文EN
#web3

ERC 4337:无需改动以太坊协议的账户抽象

ERC 4337:无需改动以太坊协议的账户抽象
13 min read
#web3

ERC 4337:无需改动以太坊协议的账户抽象

账户抽象(Account abstraction)长期以来都是以太坊开发者社区的梦想。它的理念是:EVM 代码不只用来实现应用逻辑,也用来实现单个用户钱包的验证逻辑(nonce、签名……)。这会为钱包设计打开创造力的大门,带来一些重要特性:

  • 多签与社交恢复

  • 更高效、更简单的签名算法(如 Schnorr、BLS)

  • 抗量子的签名算法(如 Lamport、Winternitz)

  • 可升级性

这些事今天用智能合约钱包其实就能做到,但以太坊协议本身要求一切都必须打包进一笔由 ECDSA 保护的外部账户(EOA)发起的交易,这让事情变得非常困难。每一个用户操作都得被一笔来自 EOA 的交易包裹,凭空多出 21000 gas 的开销。用户要么得在一个单独的 EOA 里备着 ETH 来付 gas、同时管理两个账户的余额,要么依赖中继系统——而后者通常是中心化的。

EIP 2938 是修复此问题的一条路径:它引入若干以太坊协议改动,允许顶层交易从合约而非 EOA 发起,合约本身带有矿工会检查的验证与付费逻辑。但这需要在协议开发者正全力投入合并(the merge)与扩容之际,对协议做出重大改动。在我们的新提案(ERC 4337)里,我们给出了一种无需改动共识层、就能获得同样收益的方法。

这个提案如何运作?

我们不去修改共识层本身的逻辑,而是在一个更高层的系统里复刻交易内存池(mempool)的功能。用户发送 UserOperation 对象,把用户意图连同签名和其他验证数据一起打包。矿工或使用 Flashbots 等服务的打包者(bundler),可以把一组 UserOperation 打包成单独的一笔"打包交易(bundle transaction)",再被纳入以太坊区块。

打包者用 ETH 支付这笔打包交易的费用,并通过各个 UserOperation 执行时支付的费用获得补偿。打包者会依据与现有交易内存池中矿工类似的费用优先级逻辑,来选择纳入哪些 UserOperation。UserOperation 看起来像一笔交易,是一个经 ABI 编码的结构体,包含如下字段:

  • sender:发起该操作的钱包

  • nonce 和 signature:传入钱包验证函数的参数,让钱包能验证一个操作

  • initCode:若钱包尚不存在,用来创建钱包的初始化代码

  • callData:实际执行步骤中要用什么数据来调用钱包

其余字段与 gas 和费用管理有关;完整字段列表见 ERC 4337 规范。

钱包是一个智能合约,必须具备两个函数:

  • validateUserOp:以一个 UserOperation 为输入。该函数负责验证 UserOperation 上的签名和 nonce;验证成功则支付费用并递增 nonce,验证失败则抛出异常。

  • 一个操作执行函数:把 calldata 解释为钱包要执行的指令。它如何解释 calldata、据此做什么,完全是开放式的;但我们预期最常见的行为是把 calldata 解析为让钱包发起一次或多次调用的指令。

为了简化钱包逻辑,确保安全所需的大量复杂智能合约技巧并不放在钱包本身,而是放在一个名为**入口点(entry point)**的全局合约里。validateUserOp 和执行函数都应被 require(msg.sender == ENTRY_POINT) 守卫,使得只有受信任的入口点才能让钱包执行任何动作或支付费用。入口点只有在某个携带相应 calldata 的 UserOperation 的 validateUserOp 已经成功之后,才会对钱包发起任意调用,因此这足以保护钱包免受攻击。若钱包尚不存在,入口点还负责用提供的 initCode 创建它。

运行 handleOps 时入口点的控制流

内存池节点和打包者需要对 validateUserOp 能做什么施加一些限制:尤其是,validateUserOp 的执行不能读写其他合约的存储,不能使用 TIMESTAMP 等环境操作码,也不能调用其他合约——除非那些合约可被证明不可能自毁(self-destruct)。这样才能确保打包者和 UserOperation 内存池节点为验证某个 UserOperation 是否可纳入/可转发而做的模拟执行,在它真正被纳入未来区块时会产生相同的效果。

如果一个 UserOperation 的验证已被成功模拟,那么在 sender 账户发生其他内部状态变更之前,该 UserOperation 都能保证可被纳入(状态变更可能来自同一 sender 的另一个 UserOperation,或另一个合约调入该 sender;无论哪种,针对单个账户触发这一条件都需在链上花费 7500+ gas)。此外,UserOperation 会为 validateUserOp 步骤指定一个 gas 上限,内存池节点和打包者会拒绝那些上限不够小(如超过 200000)的操作。这些限制复刻了现有以太坊交易那些让内存池免受 DoS 攻击的关键属性。打包者和内存池节点可以用类似当今以太坊交易处理的逻辑,来决定是否纳入或转发一个 UserOperation。

与常规以太坊交易内存池相比,这套设计新增、保留与牺牲了哪些属性?

保留的属性:

  • 没有中心化角色;一切都通过点对点内存池完成

  • DoS 安全(通过模拟检查的 UserOperation 保证可被纳入,直到 sender 发生另一次状态变更——这要求攻击者为每个 sender 花费 7500+ gas)

  • 用户侧无需钱包初始化的复杂性:用户无需关心其钱包合约是否"已发布";钱包存在于确定性的 CREATE2 地址上,若钱包尚不存在,第一个 UserOperation 会自动创建它

  • 完整支持 EIP 1559,包括费用设置的简便(用户可设一个固定的费用溢价和一个较高的最大总费用,并期望被快速纳入、被公平收费)

  • 支持按费用替换(replace-by-fee):发送一个溢价显著高于旧操作的新 UserOperation,以替换该操作或让它更快被纳入

新增的好处:

  • 验证逻辑的灵活性:validateUserOp 函数可加入任意的签名与 nonce 验证逻辑(新签名方案、多签……)

  • 足以让执行层抗量子:若此提案被普遍采用,执行层无需为抗量子再做额外工作。用户可各自把钱包升级为抗量子版本。连包裹交易也是安全的,因为矿工可为每笔打包交易使用一个全新创建、因而受哈希保护的 EOA,并在交易被纳入区块前不公开它。

  • 钱包可升级:钱包验证逻辑可以是有状态的,因此钱包可更换其公钥,或(若以 DELEGATECALL 发布)完全升级其代码。

  • 执行逻辑的灵活性:钱包可为执行步骤加入自定义逻辑,例如实现原子化的多操作(这是 EIP 3074 的关键目标)

弱点:

  • DoS 脆弱性略有增加:尽管协议已尽力,但仅因为验证逻辑被允许比"单次 ECDSA 验证"这一现状稍复杂一些。

  • gas 开销:比常规交易多一些 gas 开销(不过在某些用例中可由多操作支持来弥补)。

  • 一次只能一笔交易:账户无法把多笔交易排队送进内存池。但原子化多操作的能力,让这一特性的必要性大大降低。

用 paymaster 实现代付

代付交易有若干关键用例,最常被提到的两个是:

  1. 让应用开发者替其用户支付费用

  2. 让用户用 ERC20 代币支付费用,由一个合约充当中介收取 ERC20 并以 ETH 付费

本提案可通过内置的 paymaster 机制支持这一功能。一个 UserOperation 可把另一个地址设为它的 paymaster。若设置了 paymaster(即非零),在验证步骤中,入口点也会调用 paymaster,以确认它愿意为该 UserOperation 付费。若愿意,则费用从 paymaster 质押在入口点内的 ETH 中扣除(出于安全设有提款延迟),而非从钱包扣除。在执行步骤中,钱包照常以 UserOperation 里的 calldata 被调用,但之后会以 postOp 调用 paymaster。

上述两个用例的示例流程:

  • paymaster 验证 paymasterData 中是否包含来自赞助方的签名,以确认赞助方愿意为该 UserOperation 付费。若签名有效,paymaster 接受,该 UserOperation 的费用从赞助方质押中支付。

  • paymaster 验证 sender 钱包是否有足够的 ERC20 余额来支付该 UserOperation。若有,paymaster 接受并支付 ETH 费用,然后在 postOp 中收取 ERC20 代币作为补偿(若 postOp 因 UserOperation 耗尽 ERC20 余额而失败,执行将回滚、postOp 会被再次调用,因此 paymaster 总能拿到补偿)。注意目前这仅在该 ERC20 是由 paymaster 自己管理的包装代币时才可行。

特别注意第二个用例中,paymaster 可以是纯被动的,或许只偶尔做做再平衡和参数重设。相比以往那些要求 paymaster 始终在线、主动包裹每一笔交易的代付方案,这是一个巨大的改进。

这个提案进展到哪了?

ERC 4337 见此处,一个实现正在此处推进。预计很快会有一个早期开发者 alpha 版本,之后的下一步将是敲定最终细节、并进行审计以确认方案的安全性。

开发者们应该很快就能开始试验账户抽象钱包了!