---
title: "ERC-4337 dummy signatures 与 gas token 转账"
description: "了解如何在使用 dummy signature 和 dummy paymasterAndData 值的 user operation gas 估算过程中获取 preVerificationGas 和 verificationGasLimit 字段。"
---

# ERC-4337 dummy signatures 与 gas token 转账

在[ERC-4337 Gas Estimation](https://www.alchemy.com/blog/erc-4337-gas-estimation)中，我们讨论了 ERC-4337 中 gas 的工作原理以及我们的 gas 估算方法。通过这种方法，我们应该能够为用户提供提交其 user operation 所需的准确数值。然而，事情并不总是这么简单。

让我们深入探讨一些使 ERC-4337 gas 估算变得复杂的其他问题。

## 什么是 dummy `signature` 值？

在大多数智能合约账户实现中，签名字段是通过链下计算的：对一个 user operation 进行哈希运算，然后使用某种签名方案（ECDSA 最为常见）对该哈希签名。这个签名会在验证阶段由账户合约在链上验证。

例如，`SimpleAccount` [使用](https://github.com/eth-infinitism/account-abstraction/blob/d1333cf58c17d5cc84e830f3fc3a69081c777979/contracts/samples/SimpleAccount.sol#L93)一种 [EIP-191](https://eips.ethereum.org/EIPS/eip-191) 签名方案对哈希进行签名，该签名在其 `validateUserOp` 函数中通过 [OpenZeppelin](https://www.alchemy.com/dapps/openzeppelin) 的 [ECDSA library](https://docs.openzeppelin.com/contracts/2.x/api/cryptography#ECDSA-toEthSignedMessageHash-bytes32-) 在链上验证。

这个签名必须在 gas 估算之后计算，因为这些字段也被包含在哈希中。

然而，gas 估算步骤中有一部分需要签名字段已经填好：`preVerificationGas` 和 `verificationGasLimit `。

### preVerificationGas

在本系列第一部分关于 `preVerificationGas` 估算的章节中，我们讨论了 bundler 用来计算未计量 gas 的三种计算方式。

请注意，第 2 步和第 3 步（计算该 user operation 在 calldata gas 成本中的份额，以及在任何执行 gas 开销中的份额）都直接取决于 user operation 的长度和内容，其中包括 `signature` 字段。

### verificationGasLimit

几乎所有实用的智能合约账户实现都需要某种签名验证。这部分 gas 也需要被估算！这个估算过程不能 revert，否则 verification gas 就无法实现。

我们该如何选择使用哪个签名？

## 如何计算 dummy signature 值

为了解决这些问题，许多 [ERC-4337 bundler](https://www.alchemy.com/overviews/what-is-a-bundler) 使用一个“Dummy Signature”，该值必须由 `eth\_estimateUserOperationGas` 的调用方根据具体账户类型提供。

### 约束条件

这个 dummy signature 有以下几条约束：

1. dummy 值的长度应等于最大签名长度，并且必须包含该账户下有效的最大数量的非零字节。
   a. 这确保了 `preVerificationGas` 的计算能够考虑到最坏情况下签名对 calldata 和 entry point 开销成本的贡献。
1. 该 dummy 值在提供给账户的验证函数时，必须导致最坏情况下的 gas 消耗，并且不能引发 revert。
1. 该 dummy 值不应是任何有效 user operation 的有效签名。

可以在我们文档中 [eth_estimateUserOperationGas](https://www.alchemy.com/docs/wallets/api-reference/bundler-api/bundler-api-endpoints/eth-estimate-user-operation-gas) 方法的说明里找到 `SimpleAccount` 的 dummy `signature` 值。

**这个 dummy signature 具有以下特性：**

1. 其长度与 ECDSA 签名完全相同
1. 其包含 ECDSA 签名中允许的最大数量的非零字节
1. 它是一个有效的 ECDSA 签名（这样 `.recover\(\)` 调用就不会 revert）
1. 它不是任何已知 user operation 的签名，因此 `SimpleAccount` 将始终返回 `SIG\_VALIDATION\_FAILED`

账户实现者需要确保在编写验证函数时，能够支持提供 dummy signature。

**这意味着：**

1. 仅对不可能是 dummy signature 的签名使用 `REVERT`。当提供的是 dummy signature 时，返回 `SIG\_VALIDATION\_FAILED`。
1. 注意不要为 dummy signature “提前中断”失败逻辑。也就是说，dummy 值应当走完整个验证函数，并使用最大的 gas 量。
1. 在实践中，这意味着要移除所有提前返回。账户验证函数可能会较早判断出签名无效，但它应当继续运行函数逻辑，并在最后才返回失败结果。

## 如何计算 dummy `paymasterAndData` 值

以上要求同样适用于 gas 估算阶段的 `paymasterAndData` 字段：对于任何依赖 gas 字段数值（例如用于计算签名）的 paymaster 实现，我们都必须解决提供 dummy 值这一相同问题。

### 约束条件

这个 dummy `paymasterAndData` 有以下几条约束：

1. dummy 值的长度应等于最大 `paymasterAndData` 长度，并且必须包含该账户下有效的最大数量的非零字节。
   a. 这确保了 `preVerificationGas` 的计算能够考虑到最坏情况下 `paymasterAndData` 对 calldata 和 entry point 开销成本的贡献。
1. 该 dummy 值在提供给 paymaster 的验证函数时，必须导致最坏情况下的 gas 消耗，并且不能引发 revert。
1. 该 dummy 值不应是任何有效 user operation 的有效 `paymasterAndData`。

例如，一个依赖于对 user operation 哈希进行赞助签名验证的 [sponsoring paymaster](https://www.alchemy.com/overviews/what-is-a-paymaster)，在估算过程中需要提供一个具有上述类似特性的 dummy `paymasterAndData` 值：

1. dummy 值必须包含一个有效的 paymaster 合约地址
1. 用于 `preVerificationGas` 计算的最大长度和字节值
1. 提供给 paymaster 验证函数时，必须消耗最大 gas，并得到一个 `SIG\_VALIDATION\_FAILED` 返回值

Paymaster 实现者需要确保在编写验证函数时，能够支持提供 dummy `paymasterAndData`。

**这意味着：**

1. 仅对不可能是 dummy 一部分的数据使用 `revert`。改为返回 ` SIG\_VALIDATION\_FAILED`。
1. 注意不要为 dummy “提前中断”失败逻辑。也就是说，dummy 应当走完整个验证函数，并使用最大的 gas 量。
   a. 在实践中，这意味着要移除所有提前返回。paymaster 验证函数可能会较早判断出签名无效，但它应当继续运行函数逻辑，并在最后才返回失败结果。

## Gas token 转账

对 `verificationGasLimit` 的估算必须考虑验证阶段中任何 token 转账所产生的 gas 成本。许多 [user op](https://www.alchemy.com/overviews/user-operations) 会在验证阶段发生一次 token 转账，用于预先支付 gas，并在操作结束时对未消耗的 gas 进行退款。

这里有两种情况：

1. 无 Paymaster——这是从 sender 向 entry point 合约转账 ETH。
1. 有 Paymaster——这可以是任何形式的转账（在规范允许的规则范围内），但通常采用从 sender 向 paymaster 转账 ERC-20 token 的形式。

#### 如果账户资金不足会怎样？

如果 `maxFeePerGas` 被设置为非零值，那么当账户持有的 token 不足以支付费用时，验证阶段的转账会 revert。这意味着用户必须在尝试估算 gas 之前先为账户充值。

**一种目前无法实现的理想工作流程：**

1. 估算 gas
1. 为账户充值 gas
1. 发送 operation

这里一个可能的解决方案是：告诉用户在调用 `eth\_estimateUserOperationGas` 时，不设置 `maxFeePerGas`，或将其设为零。但这样会导致 gas 成本被设为零，从而使需要发生的任何 token 转账数值也为零。在[许多账户/paymaster 类型](https://github.com/eth-infinitism/account-abstraction/blob/d1333cf58c17d5cc84e830f3fc3a69081c777979/contracts/core/BaseAccount.sol#L101)中，零 gas 成本会跳过对 `transfer` 的调用。这会导致在使用零值 `maxFeePerGas` 时出现 gas 低估的问题。

另一个问题与使用非零 `maxFeePerGas` 并尝试本系列第一部分“[Attempt 3: Binary Search](https://www.alchemy.com/blog/erc-4337-gas-estimation)”中所定义的二分搜索估算方法有关。

该方法的第一步是通过使用一个最大 gas 值来确保该 operation 是可行的。但 sender 可能没有足够的资产在该最大值下支付 gas，而 bundler 也并不总是拥有足够的信息来确定手续费 token 的余额（例如 ERC-20 paymaster 的情况），从而无法确定正确的上限。

### Alchemy 的 bundler 如何解决涉及 token 转账的 gas 估算问题？

Rundler 针对 `eth\_estimateUserOperationGas` 采取的方法如下：

#### 无 paymaster 情况

- Rundler 将始终忽略 `maxFeePerGas` 和 `maxPriorityFeePerGas`，并将其设为 0。
- Rundler 将始终向 `verificationGasLimit` 添加固定的 10K gas，以计入从 sender 向 entry point 转移 ETH 存款的成本。
- 客户端无需做任何改动。

<CalloutBlock>

💡 第 1 条与 ERC-4337 规范存在偏差，该规范指出“gas limit（及价格）参数是可选的，但如果指定了就会被使用”

</CalloutBlock>

#### 有 paymaster 情况

- Rundler 将始终忽略 `maxFeePerGas` 和 `maxPriorityFeePerGas`，并将其设为 0。
- 如果任何 paymaster 逻辑依赖于手续费数值（例如 ERC-20 转账的情况），Rundler 对 `verificationGasLimit` 的估算将始终偏低。
- 使用此类 paymaster 的用户需要在客户端自行计入由非零手续费所产生的额外 gas。

例如，如果使用的是一个在验证阶段进行转账的 ERC-20 paymaster，则应始终为从 `eth\_estimateUserOperationGas` 得到的 `verificationGasLimit` 返回值增加固定的 75K gas。这要求客户端了解自己所调用的 paymaster 合约，并事先知道由转账导致的 gas 低估情况。

<CalloutBlock>

💡 Alchemy 的 [aa-sdk](https://github.com/alchemyplatform/aa-sdk) 允许 paymaster middleware [相应地修改这个 gas limit](https://github.com/alchemyplatform/aa-sdk/blob/56bc34be3a50a2709ca546ed90a980f3c489cbbe/packages/core/src/provider/types.ts#L43)。

</CalloutBlock>

## 这对开发者意味着什么？

Dummy 值和 token 转账问题会影响构建智能合约账户、paymaster 以及账户客户端的开发者。

### 智能合约账户开发者

智能合约账户开发者需要确保：根据账户验证函数的运行方式，客户端始终能够确定出一个 dummy signature 值。该签名不能引发 revert，且必须得到最大的 gas 估算结果。

### Paymaster 开发者

Paymaster 开发者必须确保：根据 paymaster 验证函数的运行方式，始终能够确定出一个 dummy `paymasterAndData` 值。该值不能引发 revert，且必须得到最大的 gas 估算结果。

<CalloutBlock>

💡 Alchemy 通过 [alchemy_requestGasAndPaymasterAndData](https://www.alchemy.com/docs/wallets/api-reference/gas-manager-admin-api/gas-abstraction-api-endpoints/alchemy-request-gas-and-paymaster-and-data) 将 gas 估算流程与模拟流程结合起来，在其 sponsoring paymaster 中为用户简化了这一过程。

</CalloutBlock>

### 账户客户端开发者

如果账户客户端开发者所对接的 paymaster 会在验证阶段执行转账操作（或任何其他基于手续费数值的逻辑），并且使用 Alchemy 的端点进行估算，则需要将与该转账相关的潜在 gas 追加到估算返回的 `verificationGasLimit` 上。

敬请期待后续文章，我们将介绍更多 ERC-4337 gas 估算方面的复杂问题！

🦀

## 继续阅读

本系列共 4 篇文章，接下来的文章将探讨在 Optimism 和 Arbitrum 等 layer 2 区块链上估算 gas 所面临的挑战，以及签名聚合器相关的问题。

本系列最后一篇文章将详细介绍 user operation 手续费估算流程。如果你错过了第一部分，快去了解 ERC-4337 gas 估算的工作原理吧！

- [How ERC-4337 Gas Estimation Works](https://www.alchemy.com/blog/erc-4337-gas-estimation)
- [L2 Gas and Signature Aggregators](https://www.alchemy.com/blog/l2-gas-and-signature-aggregators)
- [User Operation Fee Estimation](https://www.alchemy.com/blog/user-operation-fee-estimation)
