ERC-4337 是一项重要的以太坊改进提案,它通过引入账户抽象(Account Abstraction)功能,允许用户使用智能合约账户作为其主要账户,而无需依赖外部拥有账户(EOA)。该提案完全避免了共识层协议变更,通过更高层的伪交易对象 UserOperation 和独立的内存池机制来实现这一目标。
核心概念与动机
什么是账户抽象?
账户抽象旨在让用户能够使用包含任意验证逻辑的智能合约账户,完全摆脱对EOA的依赖。传统的智能合约账户和某些提案(如EIP-7702)仍要求用户同时拥有EOA,而ERC-4337彻底消除了这一需求。
设计目标
- 去中心化:允许任何捆绑者(bundler,类似于区块构建者)参与处理账户抽象的
UserOperation,所有操作通过公共内存池进行,用户无需知晓特定节点的直接通信地址。 - 无需以太坊共识变更:当前以太坊共识层开发专注于可扩展性功能,可能长期无法进行协议变更。为避免依赖共识变更,本提案采用更高层的实现方式。
- 支持多样化用例:包括隐私保护应用、原子多操作、使用ERC-20代币支付交易费用、开发者代付费用以及赞助交易等场景。
技术规范详解
关键术语定义
- UserOperation:描述用户发起的交易的结构体。包含
to、calldata、maxFeePerGas、maxPriorityFeePerGas、nonce、signature等字段,但其signature字段的使用由智能合约账户实现定义。 - 发送者(Sender):发出
UserOperation的智能合约账户。 - 入口点(EntryPoint):执行
UserOperation捆绑的单例合约。捆绑者必须将支持的入口点加入白名单。 - 捆绑者(Bundler):处理
UserOperation的节点,能够创建有效的entryPoint.handleOps()交易并将其加入区块。 - 支付主管(Paymaster):同意为用户支付交易费用的辅助合约。
- 工厂(Factory):为新发送者合约执行部署的辅助合约。
UserOperation 结构
为避免共识变更,ERC-4337 不创建新的交易类型,而是使用名为 UserOperation 的结构体:
| 字段 | 类型 | 描述 |
|---|---|---|
sender | address | 发起操作的账户地址 |
nonce | uint256 | 防重放参数 |
factory | address | 新账户的工厂地址或EIP-7702标志 |
factoryData | bytes | 工厂数据或EIP-7702初始化数据 |
callData | bytes | 主执行调用中传递给发送者的数据 |
callGasLimit | uint256 | 为主执行调用分配的Gas量 |
verificationGasLimit | uint256 | 验证步骤分配的Gas量 |
preVerificationGas | uint256 | 支付给捆绑者的额外Gas |
maxFeePerGas | uint256 | 每Gas最大费用(类似EIP-1559) |
maxPriorityFeePerGas | uint256 | 每Gas最大优先费用 |
paymaster | address | 支付主管合约地址(如为空则由发送者支付) |
paymasterVerificationGasLimit | uint256 | 支付主管验证代码分配的Gas量 |
paymasterPostOpGasLimit | uint256 | 支付主管后操作代码分配的Gas量 |
paymasterData | bytes | 支付主管数据 |
signature | bytes | 传递给发送者以验证授权的数据 |
用户将 UserOperation 对象发送到专用的 UserOperation 内存池。为防止重放攻击,signature 必须依赖于 chainid 和 EntryPoint 地址。
入口点合约接口
入口点合约的核心接口是 handleOps 函数:
function handleOps(PackedUserOperation[] calldata ops, address payable beneficiary);beneficiary 是在捆绑执行期间收集所有Gas费用的地址。
智能合约账户接口
智能合约账户必须实现以下核心接口:
interface IAccount {
function validateUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external returns (uint256 validationData);
}账户必须验证调用者是受信任的入口点,验证签名是否有效,并至少向入口点支付 missingAccountFunds。
半抽象Nonce支持
ERC-4337 使用单个 uint256 nonce值,但将其视为两个值:
- 192位"密钥"
- 64位"序列号"
这种方法在协议层面保持了链上 UserOperation 哈希的唯一性,同时允许账户实现任何自定义逻辑。
操作流程与执行机制
入口点处理流程
入口点的 handleOps 函数执行两个循环:验证循环和执行循环。
验证循环中,对每个 UserOperation 执行以下步骤:
- 如果发送者智能合约账户不存在,使用
initcode创建它 - 计算发送者需要支付的最大可能费用
- 调用发送者合约的
validateUserOp方法 - 验证账户在入口点中的存款是否足够覆盖最大可能成本
执行循环中,对每个 UserOperation 执行以下步骤:
- 使用
UserOperation的calldata调用账户 - 如果calldata以
IAccountExecute.executeUserOp的方法签名开头,则构建相应的calldata进行调用 - 调用后,将预收取的多余Gas成本退还到账户存款中
未使用的 callGasLimit 和 paymasterPostOpGasLimit Gas将征收10%的罚金,只有当剩余未使用Gas量大于等于40000时才适用此罚金。
捆绑者行为规范
当捆绑者接收到 UserOperation 时,必须运行基本健全性检查:
- 发送者是否是现有合约,或initCode不为空(但不能同时满足)
- 验证Gas限制值是否低于最大值
- 检查支付主管地址是否有效且有足够存款
- 确保Gas费用高于可接受的最低值
- 检查同一发送者没有其他UserOperation已在内存池中
应用场景与优势
多样化支付方式
ERC-4337 支持多种灵活的支付场景:
- 使用ERC-20代币支付交易费用
- 开发者为其用户支付费用
- 第三方支付和跨链Gas支付
- 赞助交易模式
增强的安全性
通过分离验证和执行阶段,ERC-4337 提供了更强大的安全保证:
- 签名验证逻辑完全由智能合约账户控制
- 支持多重签名配置和自定义恢复机制
- 防止重放攻击和DoS攻击
更好的用户体验
账户抽象显著改善了用户体验:
- 无需管理EOA私钥
- 支持社交恢复和更灵活的账户管理
- 简化了区块链交互流程
常见问题
ERC-4337 与传统账户有何不同?
传统以太坊账户分为外部拥有账户(EOA)和合约账户。EOA由私钥控制,而合约账户由代码控制。ERC-4337 允许合约账户像EOA一样发起交易,同时保持合约账户的灵活性和可编程性。
如何开始使用ERC-4337账户?
要使用ERC-4337,用户需要选择一个支持该标准的钱包应用。钱包会帮助用户创建智能合约账户,并处理所有底层的UserOperation生成和提交过程。用户体验上与传统钱包相似,但功能更加强大。
ERC-4337是否支持现有的智能合约钱包?
现有智能合约钱包需要实现 validateUserOp 函数才能与ERC-4337兼容。如果智能合约钱包已经有授权可信操作提交者的功能,可以创建一个ERC-4337兼容的包装器来实现兼容性。
捆绑者如何获得收益?
捆绑者通过打包UserOperation并将其纳入区块来获得收益。他们可以从每个UserOperation中收取一部分Gas费用作为服务费,具体比例由市场竞争决定。
ERC-4337如何防止垃圾交易攻击?
ERC-4337 通过多种机制防止垃圾交易攻击:UserOperation需要支付预验证Gas费用;捆绑者在将操作加入内存池前会进行模拟验证;对于频繁导致操作失败的实体,系统会实施信誉评分和限制机制。
安全考虑与最佳实践
入口点合约的安全性
入口点合约需要经过严格审计和形式化验证,因为它作为所有ERC-4337操作的中心信任点。虽然这种架构减少了单个账户的审计工作量,但入口点合约本身必须非常健壮。
合约升级与存储布局
大多数ERC-4337智能合约账户预计是可升级的。当更改底层实现时,所有账户必须确保两个合约的存储布局没有冲突。采用"钻石存储"(ERC-7201)是常见解决方案。
临时存储注意事项
使用临时存储(EIP-1153)的合约必须考虑到ERC-4337允许来自不同发送者地址的多个UserOperation包含在同一底层交易中。如果包含任何敏感信息或用于访问控制,必须手动清理临时存储。
ERC-4337 通过智能合约实现账户抽象,为以太坊生态系统带来了更灵活、更安全的账户管理模式,同时避免了共识层变更的复杂性。这一标准为去中心化应用开辟了新的可能性,极大地改善了用户体验和开发者灵活性。