ERC-7769: 用于 ERC-4337 的 JSON-RPC API
用于智能合约账户钱包和 ERC-4337 打包器之间通信的 JSON-RPC API 方法
Authors | Vitalik Buterin (@vbuterin), Yoav Weiss (@yoavw), Dror Tirosh (@drortirosh), Shahaf Nacson (@shahafn), Alex Forshtat (@forshtat) |
---|---|
Created | 2024-08-23 |
Discussion Link | https://ethereum-magicians.org/t/erc-7769-json-rpc-for-erc-4337-account-abstraction/21126 |
Requires | EIP-155, EIP-4337, EIP-7562 |
Table of Contents
摘要
定义新的 JSON-RPC API 方法,使 ERC-4337 钱包能够与 UserOpeation
mempool 节点和打包器通信,从而匹配以太坊交易已有的功能。
此外,还定义了一组 debug
JSON-RPC API 方法,以方便开发、测试和调试 ERC-4337 实现的问题。
动机
在 ERC-4337 中,以太坊中定义的用户交易被替换为 UserOperation
对象,其中包含执行用户请求的操作所需的所有信息。
但是,现有的以太坊 JSON-RPC API 方法不适合与 UserOperation
对象一起使用。
为了方便替代 UserOperation
mempool 的运行,重要的是 ERC-4337 协议的所有实现都有一组可以互换使用的标准化 API。
规范
定义
- 打包器 (bundler):公开 API 的节点,以便将
UserOperation
提交到网络。 打包器将一个或多个 UserOperation 收集到一个 bundle 中,并通过单个handleOps
调用将它们一起提交到EntryPoint
。
RPC 方法(eth 命名空间)
eth_sendUserOperation
eth_sendUserOperation
方法将 UserOperation
对象提交到 UserOperation mempool。
客户端必须验证 UserOperation
,并相应地返回结果。
如果请求通过了模拟并且被客户端的 UserOperation 池接受,则结果应该设置为 userOpHash
。
如果验证、模拟或 UserOperation 池包含失败,则不应返回 userOpHash
。相反,客户端应该返回失败原因。
参数:
- UserOperation 完整的 user-operation 结构体。
所有字段必须设置为十六进制值。
空的
bytes
块(例如,空的initCode
)必须设置为"0x"
- factory (工厂) 和 factoryData (工厂数据) 必须提供这两个参数,或者都不提供。
- paymaster (支付者),paymasterData (支付者数据),paymasterValidationGasLimit (支付者验证 Gas 限制),paymasterPostOpGasLimit (支付者后置操作 Gas 限制) 必须提供所有这些参数,或者都不提供。
- entryPoint (入口点) 请求应通过的
EntryPoint
合约地址。 这必须是由supportedEntryPoints
RPC 调用返回的入口点之一。
返回值:
- 如果 UserOperation 有效,客户端必须返回为其计算的
userOpHash
- 如果失败,必须返回一个带有
code
和message
的error
结果对象。 错误代码和消息应设置如下:- code: -32602 - 无效的
UserOperation
结构/字段 - code: -32500 - 交易被
EntryPoint
合约的simulateValidation
函数在钱包创建或验证期间拒绝message
字段必须设置为从EntryPoint
发出的FailedOp
事件的 “AAxx
” 错误消息
- code: -32501 - 交易被
paymaster
合约的validatePaymasterUserOp
函数拒绝message
字段应设置为来自paymaster
合约的回滚消息data
字段必须包含一个paymaster
值
- code: -32502 - 交易因违反 ERC-7562 操作码验证规则而被拒绝
- code: -32503 - UserOperation 超出时间范围:
钱包或支付者返回了一个时间范围,并且该时间范围已过期或即将过期。
data
字段应包含validUntil
和validAfter
值- 如果此错误是由
paymaster
合约触发的,则data
字段应包含paymaster
地址
- code: -32504 - 交易被拒绝,因为
paymaster
因 ERC-7562 声誉规则而被限制或禁止data
字段应包含paymaster
地址
- code: -32505 - 交易被拒绝,因为
paymaster
合约的 ERC-7562 质押或解除质押延迟太低data
字段应包含paymaster
地址data
字段应包含minimumStake
和minimumUnstakeDelay
- code: -32507 - 交易被拒绝,因为钱包签名检查失败
- code: -32508 - 交易被拒绝,因为支付者余额无法覆盖所有待处理的
UserOperations
。
- code: -32602 - 无效的
示例:
请求:
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_sendUserOperation",
"params": [
{
eip7702Auth, // an EIP-7702 authorization tuple
sender, // address
nonce, // uint256
factory, // address
factoryData, // bytes
callData, // bytes
callGasLimit, // uint256
verificationGasLimit, // uint256
preVerificationGas, // uint256
maxFeePerGas, // uint256
maxPriorityFeePerGas, // uint256
paymaster, // address
paymasterVerificationGasLimit, // uint256
paymasterPostOpGasLimit, // uint256
paymasterData, // bytes
signature // bytes
},
entryPoint // address
]
}
响应:
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x123456789012345678901234567890123456789012345678901234567890abcd"
}
示例失败响应:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"message": "AA21 didn't pay prefund",
"code": -32500
}
}
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"message": "paymaster stake too low",
"data": {
"paymaster": "0x123456789012345678901234567890123456790",
"minimumStake": "0xde0b6b3a7640000",
"minimumUnstakeDelay": "0x15180"
},
"code": -32504
}
}
支持 EIP-7702 授权
在激活了 EIP-7702 的网络上,UserOperation
对象也可以包含一个 eip7702Auth
元组。
请注意,根据 EIP-7702,只有在执行授权地址的更改时才必须提供 eip7702Auth
元组。
一旦必要的 eip7702Auth
元组被存储在链上,
用户不需要为任何后续的 UserOperation
提供相同的 eip7702Auth
元组。
另外,当使用 EIP-7702 授权的 sender
时,字段 factory
和 factoryData
具有修改后的行为。
当使用 EIP-7702 授权的 sender
时,factory
字段应该设置为完全 INITCODE_EIP7702_MARKER = 0x7702
标志。
传递此标志指示 EntryPoint
合约验证 sender
地址是否包含有效的 EIP-7702 授权。
当指定 INITCODE_EIP7702_MARKER
时,factoryData
值将直接传递给 sender
合约,
而不是 factory
合约。
这是在调用 validateUserOp
之前作为单独的调用完成的,
这意味着在验证期间将调用 sender
合约两次。
factoryData
值可以留空。在这种情况下,将不执行调用。
此 factoryData
调用的目的是为 EIP-7702 sender
合约提供在通过 validateUserOp
函数接受 UserOperation
之前初始化其存储的能力。
eth_estimateUserOperationGas
估计 UserOperation
的 Gas 值。
给定一个可选的没有 Gas 限制和 Gas 价格的 UserOperation
,返回所需的 Gas 限制。
签名字段被钱包忽略,因此该操作不需要用户的批准。
尽管如此,它可能需要放置一个“存根” signature
值,例如正确长度的 signature
字节数组。
如果 UserOperation 包含一个 eip7702Auth
元组,为了估计的目的,应该忽略签名,并且应该像它被 sender
签名一样评估该元组
参数:
- 与
eth_sendUserOperation
相同 所有 Gas 限制和费用参数都是可选的,但如果指定则会使用。maxFeePerGas
和maxPriorityFeePerGas
默认为零,因此帐户和支付者都不需要付款。 - 可选地接受
State Override Set (状态覆盖集合)
以允许用户在 Gas 估计期间修改状态。 此字段及其行为与为eth_call
RPC 方法定义的字段等效。
返回值:
- preVerificationGas (预验证 Gas) 此
UserOperation
的 Gas 开销 - verificationGasLimit (验证 Gas 限制) 验证此
UserOperation
所需的 Gas 限制估计值 - paymasterVerificationGasLimit (支付者验证 Gas 限制) 支付者验证所需的 Gas 限制估计值
仅当
UserOperation
指定Paymaster
地址时才返回 - callGasLimit (调用 Gas 限制) 内部帐户执行所需的 Gas 限制估计值
注意: 实际的 postOpGasLimit
无法可靠地估计。
支付者应向帐户提供此值,并要求在链上验证期间使用特定值。
错误代码:
与 eth_sendUserOperation
相同
如果对帐户合约的内部调用回退,或者支付者的 postOp
调用回退,则此操作也可能返回错误。
eth_getUserOperationByHash
基于 eth_sendUserOperation
返回的 userOpHash
值返回一个 UserOperation
对象。
参数
- hash
eth_sendUserOperation
返回的userOpHash
值
返回值:
- 如果
UserOperation
包含在一个区块中:- 返回完整的 UserOperation,并添加
entryPoint
、blockNumber
、blockHash
和transactionHash
。
- 返回完整的 UserOperation,并添加
- 否则,如果
UserOperation
在打包器的 mempool 中处于待处理状态:- 可以返回
null
,也可以返回完整的UserOperation
,并添加entryPoint
字段和blockNumber
、blockHash
和transactionHash
的null
值。
- 可以返回
- 否则:
- 返回
null
- 返回
eth_getUserOperationReceipt
基于 eth_sendUserOperation
返回的 userOpHash
值返回一个 UserOperation
收据对象。
参数
- hash
eth_sendUserOperation
返回的userOpHash
值
返回值:
如果 UserOperation
尚未包含在区块中,则返回 null
,或者:
- userOpHash 请求哈希
- entryPoint
- sender
- nonce
- paymaster 用于此 userOp 的支付者(或为空)
- actualGasCost - 为此
UserOperation
支付的实际金额(由帐户或支付者支付) - actualGasUsed - 此
UserOperation
使用的总 Gas,包括预验证、创建、验证和执行 - success 布尔值 - 此执行是否在没有回退的情况下完成
- reason - 如果
UserOperation
回退,则返回回退原因字节数组 - logs - 此特定
UserOperation
生成的日志,不包括同一 bundle 中其他UserOperations
的日志 - receipt
TransactionReceipt
对象。 请注意,返回的TransactionReceipt
适用于整个 bundle,而不仅仅是此UserOperation
。
eth_supportedEntryPoints
返回客户端支持的 EntryPoint
合约地址的数组。
数组的第一个元素应该
是客户端首选的 EntryPoint
合约地址。
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_supportedEntryPoints",
"params": []
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": [
"0xcd01C8aa8995A59eB7B2627E69b40e0524B5ecf8",
"0x7A0A0d159218E6a2f407B99173A2b12A6DDfC2a6"
]
}
eth_chainId
返回 EIP-155 Chain ID。
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_chainId",
"params": []
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x1"
}
RPC 方法(debug 命名空间)
此 API 必须仅在测试模式下可用,并且是兼容性测试套件所必需的。
在生产环境中,任何 debug_*
RPC 调用都应被阻止。
debug_bundler_clearState
清除支付者/帐户/工厂的打包器 mempool 和声誉数据。
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "debug_bundler_clearState",
"params": []
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": "ok"
}
debug_bundler_dumpMempool
转储当前的 UserOperation
mempool
参数:
- EntryPoint
eth_sendUserOperation
使用的入口点
返回:
array
- 当前在 mempool 中的 UserOperation
对象数组。
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "debug_bundler_dumpMempool",
"params": ["0x1306b01bC3e4AD202612D3843387e94737673F53"]
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
sender, // address
nonce, // uint256
factory, // address
factoryData, // bytes
callData, // bytes
callGasLimit, // uint256
verificationGasLimit, // uint256
preVerificationGas, // uint256
maxFeePerGas, // uint256
maxPriorityFeePerGas, // uint256
signature // bytes
}
]
}
debug_bundler_sendBundleNow
强制打包器从 mempool 构建并执行一个 bundle 作为 handleOps()
交易。
返回:transactionHash
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "debug_bundler_sendBundleNow",
"params": []
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": "0xdead9e43632ac70c46b4003434058b18db0ad809617bd29f3448d46ca9085576"
}
debug_bundler_setBundlingMode
设置打包模式。
在将模式设置为“manual”后,需要显式调用 debug_bundler_sendBundleNow
才能发送 bundle。
参数:
mode - ‘manual’ |
‘auto’ |
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "debug_bundler_setBundlingMode",
"params": ["manual"]
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": "ok"
}
debug_bundler_setReputation
设置给定地址的声誉。
参数:
-
要添加/替换的声誉条目的数组,其中包含以下字段:
address
- 要设置声誉的地址opsSeen
- 具有该实体的用户操作被看到并添加到 mempool 的次数opsIncluded
- 使用此实体的用户操作被包含在链上的次数
-
EntryPoint
eth_sendUserOperation
使用的入口点
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "debug_bundler_setReputation",
"params": [
[
{
"address": "0x7A0A0d159218E6a2f407B99173A2b12A6DDfC2a6",
"opsSeen": "0x14",
"opsIncluded": "0x0D"
}
],
"0x1306b01bC3e4AD202612D3843387e94737673F53"
]
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": "ok"
}
debug_bundler_dumpReputation
返回所有观察到的地址的声誉数据。
返回声誉对象数组,每个对象都包含上面 debug_bundler_setReputation
中描述的字段。
参数:
- EntryPoint
eth_sendUserOperation
使用的入口点
返回值:
声誉条目的数组,其中包含以下字段:
address
- 要设置声誉的地址opsSeen
- 具有该实体的用户操作被看到并添加到 mempool 的次数opsIncluded
- 使用此实体的用户操作被包含在链上的次数-
status
- (字符串) 地址在打包器中的状态 ('ok'
'throttled'
'banned'
)
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "debug_bundler_dumpReputation",
"params": ["0x1306b01bC3e4AD202612D3843387e94737673F53"]
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": [
{ "address": "0x7A0A0d159218E6a2f407B99173A2b12A6DDfC2a6",
"opsSeen": "0x14",
"opsIncluded": "0x13",
"status": "ok"
}
]
}
debug_bundler_addUserOps
将 UserOperation
对象数组注入到 mempool 中。
假设给定的 UserOperation
对象都通过了验证,而没有实际验证它们,
并将它们直接接受到 mempool 中。
参数:
UserOperation
对象数组
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "debug_bundler_addUserOps",
"params": [
[
{ sender: "0xa...", ... },
{ sender: "0xb...", ... }
]
]
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": "ok"
}
理由
- 显式调试功能:打包器需要提供一组调试功能,以便可以使用“打包器规范测试套件”来验证其是否符合规范。
向后兼容性
此提案定义了一个新的 JSON-RPC API 标准,该标准不会造成任何向后兼容性挑战。
安全注意事项
防止 UserOperation mempool 上的 DoS 攻击
运行公共生产 ERC-4337 节点是一项计算密集型任务,并且可能是 DoS 攻击的目标。
这通过 ERC-7562 验证规则来解决,该规则定义了一种 ERC-4337 节点跟踪参与者
声誉以及防止节点接受恶意制作的 UserOperations
的方法。
强烈建议所有 ERC-4337 节点也实施 ERC-7562 验证规则,以最大限度地降低 DoS 风险。
在生产服务器中禁用 debug
API
debug
命名空间中定义的 API 并非旨在公开可用。
ERC-4337 的生产实现绝不能默认使其可用,
事实上,启用它应该会导致明确警告暴露此 API 的潜在危险。
版权
通过 CC0 放弃版权及相关权利。
Citation
Please cite this document as:
Vitalik Buterin (@vbuterin), Yoav Weiss (@yoavw), Dror Tirosh (@drortirosh), Shahaf Nacson (@shahafn), Alex Forshtat (@forshtat), "ERC-7769: 用于 ERC-4337 的 JSON-RPC API [DRAFT]," Ethereum Improvement Proposals, no. 7769, August 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7769.