本文提出了一种综合的原生账户抽象提案,该提案将以太坊交易范围分为多个步骤:验证、执行和交易后逻辑。通过引入新交易类型和多个执行框架,提升了账户抽象的灵活性和效率,同时保持与ERC-4337生态系统的向后兼容性,解决了许多现有问题。
将 EIP-2938 和 ERC-4337 整合成一个全面的原生账户抽象提案。
我们提议将以太坊交易范围分成多个步骤:验证、执行和交易后逻辑。交易的有效性由交易的验证步骤的结果决定。
我们进一步将交易的验证分为授权和Gas费支付两个目的,从而允许合约 B 为将由账户合约 A 执行的交易支付Gas费。
这些好处在于与新兴的 ERC-4337 生态系统保持向后兼容,同时实现原生账户抽象的长期目标。
作为一个完全自愿的 ERC,ERC-4337 能做很多事情。然而,与原生支持相比,任何超协议的方法都面临几个缺点。有几个关键领域使得它比真正的协议内解决方案弱:
现有用户不能从中受益,或者在不将所有资产和活动迁移到新账户的情况下升级使用。
基本 UserOperation
的额外Gas收费约为 42k,而基本交易的约为 21k。
来自协议内审查抵抗技术(如 crLists)的好处较少,这些技术针对交易而忽略了 UserOperations
。
依赖于更小的参与节点集合和非标准 RPC 方法,如 eth_sendRawTransactionConditional
。
无法使用 tx.origin
或依赖于它的合约,因为它返回的是处理者的无意义地址。
EIP-2938 定义了一种非常成熟的账户抽象替代方法。然而,在没有任何协议更改的情况下,它并不适合在生产中使用的 ERC-4337 架构。因此,EIP-2938 的实施将不会从使用 ERC-4337 获得的生产经验和与其保持向后兼容中获益。
未来,在某个时点,以太坊上的 EOA 可能会被预先部署的智能合约替代。然而,这在没有将原生账户抽象添加到该协议的情况下是不可能的。
名称 | 值 |
---|---|
FORK_BLOCK | TBD |
AA_TX_TYPE | 4 |
AA_ENTRY_POINT | address(7560) |
AA_SENDER_CREATOR | address(ffff7560) |
AA_NONCE_MANAGER | TODO |
AA_BASE_GAS_COST | 15000 |
AA_ECRECOVER_COST | 6000 |
VERSION | 1 |
MAGIC_VALUE_SENDER | 0xbf45c166 // bytes4(keccak256("validateTransaction(uint256,bytes32,bytes)")) |
MAGIC_VALUE_PAYMASTER | 0xe0e6183a // bytes4(keccak256("validatePaymasterTransaction(uint256,bytes32,bytes)")) |
MAX_CONTEXT_SIZE | 65536 |
UNUSED_GAS_PENALTY | 10 |
引入新的 EIP-2718 交易类型 AA_TX_TYPE。这种类型的交易被称为“AA交易”。其有效载荷应被解释为:
0x04 || 0x00 || rlp([
chainId, sender, nonce, builderFee,
callData, paymasterData, deployerData,
maxPriorityFeePerGas, maxFeePerGas,
validationGasLimit, paymasterGasLimit, callGasLimit,
accessList, signature
])
此交易的基本Gas费用被设置为 AA_BASE_GAS_COST,而不是 21000,以反映缺乏 “内在” ECDSA 签名验证。
如果指定了 paymasterData
,其前 20 字节将包含 paymaster
合约的地址。
如果指定了 deployerData
,其前 20 字节将包含 deployer
合约的地址。
在某些情况下,区块构建者可能希望将 AA_TX_TYPE
交易数组拆分为进行验证和执行的单个批次。
没有头交易类型时,只能通过创建一个人工的遗留类型交易来实现这一点。相反,我们提议引入一个明确的“计数”交易子类型。
它们的有效载荷应该被解释为:
0x04 || 0x01 || rlp([chainId, transactionCount])
头交易的独特哈希计算如下:
keccak256(AA_TX_TYPE || 0x01 || rlp(chainId, transactionCount, blockNumber, txIndex))
为了实现唯一的头交易ID,将 blockNumber
和 txIndex
参数添加到哈希中。
头交易仅用于帮助执行客户端确定 AA_TX_TYPE
交易属于每个单独批次的数量。如果在 AA_TX_TYPE
交易之前的任何位置检测到头交易,则该区块无效。\
如果包括头交易,则区块中的所有 AA_TX_TYPE
交易都必须由其覆盖。
头交易不会影响区块链状态,并且不需消耗任何Gas。
在 RIP-7560 之前,对于与代码关联的账户(智能合约),当账户执行 CREATE
(0xf0
) 操作码时,仅使用和递增账户的计数器。
但是,使用智能合约账户时,会对某些用例造成瓶颈。例如,一个由多方同时操作的账户将要求这些参与者协调他们的交易,避免相互作废。
另一个限制可能出现于有单独执行流的情况。配置更改可能需要多个参与者共同签署一次交易,但正常操作则不需要。使用顺序计数器时,所有操作必须在配置更改执行之前暂停。
为了解决这一问题,我们建议引入一个单独的二维计数器,在合约发起交易时使用。
交易的 nonce
参数应被解释为 uint192 key || uint64 seq
值。合约账户的 nonce 被定义为映射 address account => uint192 key => uint64 seq
。这种方法保证了唯一的交易 nonce 和哈希,但取消了 nonce 为连续数字的要求。
该 nonce
在位于 AA_NONCE_MANAGER 地址的预部署合约中暴露给 EVM。
在执行其余验证代码之前,nonce
会在链上 验证和递增。
旧的 nonce
账户参数仍然适用于由 EOA 发起的交易和为 CREATE
操作码的交易。
if evm.caller == AA_ENTRY_POINT:
validate_increment()
else:
get()
def get():
if len(evm.calldata) != 44:
evm.revert()
// sender 地址,uint192 key
address = to_uint160_be(evm.calldata[0:20])
key = to_uint192_be(evm.calldata[20:44])
nonce = storage.get(keccak(address, key))
evm.return((key << 64) + nonce)
def validate_increment():
address = to_uint160_be(evm.calldata[0:20])
key = to_uint192_be(evm.calldata[20:44])
nonce = to_uint64_be(evm.calldata[44:52])
current_nonce = storage.get(keccak(address, key))
if (nonce != current_nonce):
evm.revert()
storage.set(keccak(address, key), current_nonce + 1)
TODO.
AA_TX_TYPE 交易的最大Gas费用定义为:
maxPossibleGasCost = AA_BASE_GAS_COST +
callGasLimit +
paymasterGasLimit +
validationGasLimit
如果未指定 paymaster
,则 maxPossibleGasCost
会在任何计算发生之前,从 sender
地址的余额中向前收取。如果指定了 paymaster
,则Gas费用会从其余额中收取。如果预先收费的账户余额不足,无论是 sender
还是 paymaster
,则交易无效。交易执行结束后,已预收费的地址可能会获得Gas退款。
对于所有现有交易类型,data
参数按字节收费 G_txdatazero (4 gas) 和 G_txdatanonzero (16 gas)。
交易类型 AA_TX_TYPE 引入以下动态长度输入:callData
、paymasterData
、deployerData
、signature
。这些参数的Gas费用计入交易数据成本。此交易数据Gas费用被称为 calldataCost
,并在执行交易之前从 validationGasLimit
中减去。如果 validationGasLimit
小于 calldataCost
,则交易被视为无效。
由于我们需要考虑区块构建者为将 AA_TX_TYPE
交易纳入其区块所需的额外离线工作,以及在 L2 汇总上操作的构建者可能的 L1 Gas费用,并且由于这项工作与验证所花费的Gas量无关且与Gas价格无关,因此 sender
可能决定支付额外的 builderFee
作为对区块构建者的“小费”。
该值以 wei 为单位,从 sender
或指定的 paymaster
传递到当前区块的 coinbase
,作为Gas预充的一部分。
使用 validationGasLimit
、paymasterGasLimit
和 callGasLimit
字段为自身保留大量Gas的 AA_TX_TYPE 交易,但未使用预留Gas,对区块构建者构成挑战。特别是在交易使用的Gas可能根据其在区块中的位置而存在显著差异的情况下,因为此类交易可能会导致区块构建者多次迭代其算法,直到找到一个完全利用的区块。
从交易的 sender
或 paymaster
收取 UNUSED_GAS_PENALTY
百分比的所有未使用Gas限制的罚款。
总Gas限制计算为 totalLimit = validationGasLimit + paymasterGasLimit + callGasLimit
。\
实际使用的 totalGasUsed
Gas总计为交易中使用的所有Gas之和。\
未使用Gas计算预留为 unusedGas = totalLimit - totalGasUsed
。
所有现有交易类型仅具有隐式验证阶段,其中检查余额、nonce 和签名,还有一个单一的顶部执行框架,满足 tx.origin == msg.sender
,这种情况由交易 ECDSA 签名确定。
而在处理 AA_TX_TYPE 类型交易时,将创建多个执行框架。可能的完整框架列表尝试重复 ERC-4337 流程:
nonce
验证和递增框架(必需)sender
部署框架(每个账户一次)sender
验证框架(必需)paymaster
验证框架(可选)sender
执行框架(必需)paymaster
交易后框架(可选)所有“验证阶段”中的执行框架必须成功完成而不发生回滚,并且 sender
和 paymaster
验证框架的返回值必须分别包含 MAGIC_VALUE_SENDER
和 MAGIC_VALUE_PAYMASTER
以使交易在区块中的当前位置被视为有效。
在区块有效性方面,所有验证和执行框架可以在被包含在区块时读取和写入任何状态。然而,内存池中的 AA 交易应通过存储访问规则约束以避免对区块构建者的拒绝服务攻击。这些规则在 ERC-7562 中定义。
在所有顶层框架中,全局变量具有以下含义:
操作码名称 | Solidity 等效 | 值 |
---|---|---|
CALLER |
msg.sender |
AA_ENTRY_POINT 地址。AA_SENDER_CREATOR 用于“部署框架”。 |
ORIGIN |
tx.origin |
交易的 sender 地址 |
CALLDATA* |
msg.data |
交易数据设置为相应框架的输入 |
NonceManager
将使用以下数据调用:
abi.encodePacked(sender, nonce)
deployer
地址被调用,使用 deployerData[20:]
作为调用数据输入。必须注意的是,deployer
不能 从 AA_ENTRY_POINT
被调用,而必须从 AA_SENDER_CREATOR
被调用。这是为了确保 AA_ENTRY_POINT
在完成成功验证之前无法启动对 sender
执行函数的调用。
此框架的Gas限制设置为 validationGasLimit
。此框架使用的Gas量称为 senderCreationGasUsed
。
发件人部署框架必须导致发件人地址与合约代码初始化。
我们定义以下 Solidity 结构来表示链上的 AA 交易:
struct TransactionType4 {
address sender;
uint256 nonce;
uint256 validationGasLimit;
uint256 paymasterGasLimit;
uint256 callGasLimit;
uint256 maxFeePerGas;
uint256 maxPriorityFeePerGas;
uint256 builderFee;
bytes paymasterData;
bytes deployerData;
bytes callData;
bytes signature;
}
然后定义以下 Solidity 方法,并调用相应数据的交易发送者:
function validateTransaction(uint256 version, bytes32 txHash, bytes transaction) external returns (uint256 validationData);
此框架的Gas限制设置为 validationGasLimit - senderCreationGasUsed - calldataCost
。\
transaction
参数被解释为 TransactionType4
的 ABI 编码。\
txHash
参数表示 AA_TX_TYPE 交易的哈希,签名为空,如 交易类型 AA_TX_TYPE 哈希计算 一节所定。\
version
参数被添加,以便在未来对该结构进行更改时保持 Solidity 方法 ID。
本框架使用的Gas量称为 senderValidationGasUsed
。
该框架必须返回 32 字节的 validationData
,解释为:
abi.encodePacked(MAGIC_VALUE_SENDER, validUntil, validAfter)
为允许Gas估算确定完成成功所需的Gas量,而无需实际的 signature
值,此函数应在无效签名的情况下避免回滚,并应返回不同于 MAGIC_VALUE_SENDER
的值。
validUntil
类型为 6 字节时间戳值,或零为“无限”。交易仅在此时间之前有效。validAfter
类型为 6 字节时间戳。该交易仅在此时间之后有效。
validateTransaction
函数可以选择在满足任何条件时回滚,这些条件在Gas估算期间是可以满足的。
如果指定,则交易的 paymaster
被调用,使用以下数据:
function validatePaymasterTransaction(uint256 version, bytes32 txHash, bytes transaction) external returns (bytes context, uint256 validationData);
此框架的Gas限制设为 paymasterGasLimit
。
此框架使用的Gas量称为 paymasterValidationGasUsed
。
transaction
参数被解释为 TransactionType4
的 ABI 编码。\
txHash
参数表示 AA_TX_TYPE 交易的哈希,签名为空,如 交易类型 AA_TX_TYPE 哈希计算 一节所定。
该框架必须返回一个字节数组,被解释为:
abi.encode(context, MAGIC_VALUE_PAYMASTER, validUntil, validAfter)
与 sender
验证框架 中相同,为支持Gas估算,此框架应在满足条件之前返回不同于 MAGIC_VALUE_PAYMASTER
的值。
context
字节数组的大小不得超过 MAX_CONTEXT_SIZE
,才能使交易被视为有效。
sender
地址被调用,使用 callData
输入。
此框架的Gas限制设为 callGasLimit
。\
calldataCost
值的计算在 针对交易输入收取的Gas费用 节中定义。\
此框架使用的Gas量称为 gasUsedByExecution
。
如果执行框架回滚,验证框架不会回滚。postPaymasterTransaction
仍可以在 success: false
标志下被调用。
在发送者执行框架结束后,paymaster
可能需要执行一些交易后逻辑,例如进行某种清理或账务。如果Gas支付验证返回非零的 context
,则 paymaster
会再次调用,使用以下输入:
function postPaymasterTransaction(bool success, uint256 actualGasCost, bytes context) external;
actualGasCost
参数是 paymaster
为此交易实际支付的金额,而 success
表示该交易的执行框架是否成功完成而无回滚。
该框架的Gas限制设置为 paymasterGasLimit - paymasterValidationGasUsed
。
在 postPaymasterTransaction
框架中的回滚也会使交易的执行框架回滚。验证框架不会回滚,如果 postPaymasterTransaction
框架发生回滚,仍会包括回滚执行框架的Gas费用。
由账户抽象交易确定的执行流程通过以下流程图可视化:
原生账户抽象交易的执行流程
在执行层,区块的交易有效性条件扩展为:
func validateAccountAbstractionTransaction(tx *Transaction) {
assert !(sender.code.length > 0 && deployerData.length > 0)
if (sender.code.length == 0 && deployerData.length == 0) {
validUntil = (nonce >> 112) & 0xffffffffffff
validAfter = (nonce >> 160) & 0xffffffffffff
assert Date.now() <= validUntil
assert Date.now() >= validAfter
}
if (sender.code.length == 0 && deployerData.length > 0) {
assert deployerData.length >= 20
deployer := deployerData[0:20]
calldataCost := calculateCalldataCost(tx)
retDeployer, error := evm.Call(
from: AA_SENDER_CREATOR,
to: deployer,
input: deployerData[20:],
gas: validationGasLimit - calldataCost)
assert error == nil
assert sender.code.length > 0
}
if (paymasterData.length > 0) {
assert paymasterData.length >= 20
paymaster := paymasterData[0:20]
paymasterInput := ABI.encodeWithSelector('validatePaymasterTransaction', tx, tx.hash)
retPaymaster, error := evm.Call(
from: AA_ENTRY_POINT,
to: paymaster,
input: paymasterInput,
gas: paymasterGasLimit)
assert error == nil
assert Date.now() <= retPaymaster.validUntil
assert Date.now() >= retPaymaster.validAfter
assert retPaymaster.isValid
}
if (sender.code.length == 0) {
signer := ecrecover(tx.hash, tx.signature)
assert signer == sender.address
} else {
senderInput := ABI.encodeWithSelector('validateTransaction', tx, tx.hash);
retSender, error := evm.Call(
from: AA_ENTRY_POINT,
to: sender,
input: senderInput,
gas: validationGasLimit - retDeployer.gasUsed)
assert error == nil
assert Date.now() <= retSender.validUntil
assert Date.now() >= retSender.validAfter
assert retSender.isValid
}
}
为了防御 DoS 攻击向量,执行内存池交易验证的区块构建者应考虑 ERC-7562 中描述的操作码禁用规则和存储访问规则。
区块验证 需要的工作量大致与没有 AA 交易的情况下相同。在任何情况下,验证必须执行整个区块以验证状态更改。在此执行过程中,它目前验证签名、nonce 和Gas支付。通过账户抽象,它还将验证所有验证框架是否成功。
由于需要存储从 paymaster
验证框架传递到其交易后框架中 context
值的存储,因此所需内存略有增加。
只要所有交易验证步骤返回正确值,区块即被视为有效。愿意放宽验证框架应用规则的区块构建者,可以自由这样做。
此类交易不得通过默认交易内存池传播,因其将被节点拒绝,而发送节点将被阻止为垃圾邮件发送者。它们可能在允许其明示传播的替代内存池中传播,如 ERC-7562 所定义。
用 AA 交易填充区块对于区块构建者不应构成挑战。然而,如果每笔交易在执行期间能够更改影响内存池中另一笔交易的有效性的任何状态,则区块构建者将被迫在每次包含后重新验证内存池中的所有交易。
我们通过首先将一串 AA 交易中的所有验证框架的所有更改应用,然后让所有执行框架在其后立即进行,从而减轻这一点的影响。
理论上,验证框架也可能会使彼此失效,但我们定义了方法,以通过在 ERC-7562 中应用某些规则来防止这种情况发生。
选择不强制遵循 ERC-7562 规则的构建者 必须 注意在将每笔交易包含到区块中时,根据中块状态重新验证该交易。否则,所生成的区块很可能会变得无效。
以下是包含多个账户抽象交易的区块的可视化表示。AA 交易的验证部分被单独执行,但在区块数据中并不表示为单独的交易。
包含多个原生账户抽象交易的区块结构
放大一个单独的交易时,AA 交易的验证部分可能包括多个执行框架:
在一个区块中的一个原生账户抽象交易内的框架
AA_TX_TYPE 交易的验证框架被客户端表示为单独的虚拟交易。它们被分配自己的顺序 transactionIndex
,并且其 transactionHash
定义为 (AA_TX_TYPE 交易哈希 + 1
)。
所有与区块相关的 RPC 方法,如 eth_getBlockByHash
和 eth_getBlockByNumber
,必须将这些虚拟交易包括在 transactions
字段中,并包括在区块交易计数中。
所有与交易相关的 RPC 方法,如 eth_getTransactionByHash
和 eth_getTransactionReceipt
,必须接收虚拟交易哈希作为输入,并返回如同验证为单独交易计算的详细信息。
Ethereum 定义了一系列行为,对交易范围内产生影响。此列表包括但不限于:
任何此类行为在“验证虚拟交易”和“执行交易”中具有不同影响。
Gas退款是在整个交易结束时发放。
Paymaster 验证框架
和 Sender 验证框架
各自返回值 validUntil
和 validAfter
。如果交易是由 EOA 发起的,这些字段可以被编码到 nonce
的未使用位中。
该值允许 sender
和 paymaster
合约为交易指定一个有效区块的时间范围。
交易不能包含在超出此时间范围的区块中。如果包括,则该区块被视为无效。
设置 validUntil = 0
和 validAfter = 0
将禁用该检查。
keccak256(AA_TX_TYPE || 0x00 || rlp(transaction_payload)
请注意,chainId
和 accessList
参数被包括在交易哈希计算中,但不作为 TransactionType4
结构的一部分在链上可用。
为了计算在签署交易时使用的交易哈希以及发送者验证交易签名,signature
参数的值被视为空字节数组。
sender
以实现原生Gas抽象在 sender
地址没有部署任何代码且 deployerData
长度为零的情况下,将 signature
参数解释为 (y_parity, r, s)
,将 nonce
参数解释为 (validUntil, validAfter, nonce)
。使用默认的 ECDSA 签名验证替换发件人验证框架。还要检查区块时间戳是否在 [validUntil, validAfter]
范围内。
在这种情况下,基本交易Gas成本增加 AA_ECRECOVER_COST
。
此时,callData
参数被解释为以下内容:
target || value || data
在验证一个区块时,对区块的有效性条件进行如下扩展:
for txIndex := 0; txIndex < range block.Transactions.Len(); txIndex++ {
// 1. 保存当前交易
txCurr = block.Transactions[txIndex]
if (txCurr.Type() == AccountAbstractionTransaction) {
// 2. 开始对 AA 交易进行验证
for j := txIndex; j < range block.Transactions().Len(); j++ {
tx = block.Transactions[j]
// 3. 在遇到非 AA 交易后停止(或到达区块结尾)
if (tx.Type() != AccountAbstractionTransaction) {
break
}
context[j], paymasterValidationGasUsed[j], error := validateAccountAbstractionTransaction(tx)
assert error == nil
}
// 4. 如果所有验证成功,返回保存的交易索引并运行所有执行
for j := txIndex; j < range block.Transactions().Len(); j++ {
tx = block.Transactions[j]
if (tx.Type() != AccountAbstractionTransaction) {
break
}
retCall, error := evm.Call(
from: AA_ENTRY_POINT,
to: sender,
input: callData,
gas: callGasLimit)
txIndex := j // 交易已执行-无需在外循环中重新访问
// 5. 如果需要,运行 paymaster 的交易后逻辑
if (context[j].Len() == 0){
continue
}
paymasterPostTransactionInput := ABI.encodeWithSelector('postPaymasterTransaction', success, actualGasCost, context[j])
retPostTransaction, error := evm.Call(
from: AA_ENTRY_POINT,
to: paymaster,
input: paymasterPostTransactionInput,
gas: paymasterGasLimit - paymasterValidationGasUsed[j])
}
}
else {
// 处理其他类型的交易
evm.Apply(txCurr)
}
}
eth_sendTransaction
和 eth_sendRawTransaction
接受交易类型 AA_TX_TYPE
。
成功调用后返回值不变。
如果失败,必须返回错误结果对象,其中包含代码和消息。错误代码和消息应如下所示:
代码:-32500 - 交易验证失败,由 sender
引起。
消息字段应设置为 sender
的回滚消息。
代码:-32501 - 交易验证失败,由 paymaster
引起。
消息字段应设置为 paymaster
的回滚消息。
代码:-32502 - 由于验证框架中的存储或操作码规则违反,交易被拒绝。 消息字段应设置为被违反规则的位置和描述。
代码:-32503 - 交易超出时间范围。
代码:-32504 - 交易被拒绝,因为 paymaster
被限制或禁止,正如 ERC-7562 所定义。
代码:-32505 - 交易被拒绝,因为 factory
被限制或禁止。
代码:-32506 - 交易被拒绝,因为 sender
被限制或禁止。
eth_signTransaction
接受交易类型 AA_TX_TYPE
。
返回签署使 AA_TX_TYPE
交易有效的 signature
字段的 RLP 编码交易对象。
如果此操作无法由 RPC 端点执行,则返回错误对象。
eth_getTransactionReceipt
接受封装交易 AA_TX_TYPE
的验证框架的虚拟交易的哈希。此交易的 ID 定义为 (AA_TX_TYPE 交易哈希 + 1
)。
如果 AA 交易被包含在一个区块中,则在现有字段之外返回以下值:
名称 | 值 |
---|---|
sender | 此交易的发件人地址 |
nonce | 交易的 nonce 值 |
paymaster | 如果支付交易的则为 Paymaster 地址,否则为 null |
deployer | 如果包含在交易中的 Deployer 地址,则为该地址,否则为 null |
senderCreationGasUsed | 发件人部署框架实际使用的Gas量 |
senderValidationGasUsed | 发件人验证框架实际使用的Gas量 |
paymasterValidationGasUsed | Paymaster 验证框架实际使用的Gas量 |
接受交易类型 AA_TX_TYPE
的哈希。
如果 AA 交易被包含在一个区块中,则在现有字段之外返回以下值:
名称 | 值 |
---|---|
status | 执行框架的状态为 1(成功)或 0(失败) |
executionGasUsed | 执行框架实际使用的Gas量 |
postPaymasterTransactionStatus | postPaymasterTransaction 框架的状态为 1(成功),0(失败)或 null (没有运行) |
postPaymasterTransactionGasUsed | paymaster postPaymasterTransaction 框架实际使用的Gas量 |
注意,由于在 AA_TX_TYPE 交易中没有明确的 target
,因此字段 to
没有被包括在内。
eth_call
接受交易类型 AA_TX_TYPE
,所有字段(除了 from
和 callData
)均可选。
返回 发送者执行框架 的返回值。
如果提供了 paymasterData
和 deployerData
,也会执行相应框架。
如果任何框架发生回滚,调用将返回每个回滚框架的回滚数据。
eth_estimateGasAccountAbstraction
接受交易类型 AA_TX_TYPE
,字段 validationGasLimit
、paymasterGasLimit
和 callGasLimit
可选。
可选可以接受状态覆盖集,允许用户在Gas估算期间修改状态。此字段及其行为等同于为 eth_call
RPC 方法定义的字段。
返回 {validationGasLimit, paymasterGasLimit, callGasLimit, builderFee}
对象。
注意,deployerData
和 paymasterData
字段是获得一致结果的条件。
正如前面所提到的,sender
和 paymaster
合约在验证失败时不应回滚,并且应返回不同于 MAGIC_VALUE_SENDER
或 MAGIC_VALUE_PAYMASTER
的值,以便启用Gas估算。
对智能合约账户实现这种行为的一种可接受方法是将 signature
参数与预定的“虚拟签名”进行比较,并在值匹配的情况下返回而不回滚。这不会导致交易被授权,只要返回值不包括 MAGIC_VALUE_SENDER
。
参与此账户抽象提案的合约,如 sender
或 paymaster
,必须知道要执行的代码及其提供的校验数据,以验证交易。
我们认为,最直接的实施方案是依赖于 Solidity 4 字节方法选择器,因为这是一个成熟的事实标准。
AA_TX_TYPE
交易发起交易虽然允许 EOA 发起 AA_TX_TYPE
交易似乎与账户抽象的目的相矛盾,但我们认为这实际上对智能合约账户的采用可能是重要的。
这将使所有现有的 EOA 能够受益于改进的用户体验功能,如Gas抽象和有效性范围。
将来,这可以用于为向 EOA 地址添加代码的交易支付Gas, 一旦以太坊实现诸如 EIP-5003: 用 AUTHUSURP 插入代码到 EOA, EIP-6913: SETCODE 指令 和 EIP-7377: 迁移交易 提议的更改。
本 EIP 保留了 ERC-4337 设立的大多数设计元素。这允许相同的客户端代码和智能合约在两个系统中以最少或没有更改的方式使用,同时提供显著的用户体验提升。
现有合约不受这些更改的显著影响。假设 tx.origin
被保证为 EOA 不再有效。假设 tx.origin
是支付当前交易的地址也不再有效。
任何期望以太坊交易为单个顶层执行框架的代码将不得不适应新的交易类型。
EIP-3607 对具有已部署代码的发送者的交易进行了禁止。这一限制不适用于 AA_TX_TYPE 交易。
ERC-4337 并非协议变更,可以在本 EIP 并行运行。考虑到 ERC-4337 的相似性,相同的区块构建者可能轻松支持 ERC-4337 和 AA_TX_TYPE
交易。
EntryPoint
升级到适配器合约ERC-4337 背后的团队将提供合约的参考实现,转换 paymaster
和 sender
合约的 ABI。该适配器可以被 ERC-4337 合约设置为受信任的 EntryPoint
地址。
sender
合约可以在过渡期间支持 ERC-4337 和 AA_TX_TYPE
交易,只要本 EIP 可能会被一些链采用而不被其他链采用。
以下是关于原生账户抽象的已知安全考虑的一个非详尽列表。
在验证框架结束时存在的状态可能被不相关的合约观察或修改,在执行框架开始之前。
Sender
合约必须非常谨慎,确保其代码没有做出任何错误假设。
维护一个内存池并生成有效区块所需的计算量和可用内存显著增加。
这个EIP为智能合约增加了一种新的方式,可以通过从一个具有与 validateTransaction
、validatePaymasterTransaction
对应的方法 ID 的函数返回有效值来直接扣除其余额。
这为意外或恶意包含这些方法的合约,且并未公开这些合约可以作为 sender
或 paymaster
在 AA_TX_TYPE
交易中使用,创造了一种新的风险。
虽然通过要求这些合约返回 MAGIC_VALUE_SENDER
或 MAGIC_VALUE_PAYMASTER
来部分缓解这一问题,但代码审查人员仍应注意这一点。
即使被回滚,现有交易类型也会被包括在区块中,并提供回滚原因以供调试使用。
导致交易未能上链的原因列表非常短:
对于发生在 AA_TX_TYPE
交易的验证阶段的回滚情况并非如此。
为了应对这一问题,开发人员应追踪这些交易的签署有效性,并被鼓励依赖 validUntil
时间范围参数,以确保在预定时间内未被包含的交易不会意外地再次对发送者变得有效。
通过 CC0 放弃版权及相关权利。
- 原文链接: github.com/eth-infinitis...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!