Paymasters

Overview of the different paymaster flows and use cases.

Paymasters are specialized accounts designed to subsidize transaction fees for users, enhancing usability and flexibility within protocols. They also facilitate the payment of fees using ERC20 tokens, instead of the default ETH.

Interacting with Paymasters

To utilize a paymaster, users must specify a non-zero paymaster address in their EIP712 transaction, accompanied by relevant data in the paymasterInput field.

Paymaster Verification Rules

  • Verification rules are not fully enforced yet.
  • Paymasters that do not comply with these rules may cease to function correctly in the future.

To mitigate potential DoS attacks by malicious paymasters, a reputation scoring system similar to EIP4337 is used. Unlike in EIP4337, paymasters in our system can interact with any storage slots and are not throttled under specific conditions, such as time elapsed since the last successful verification or consistent slot access patterns.

Built-in Paymaster Flows

Paymasters can operate automatically or require user interaction, depending on their design. For instance, a paymaster that exchanges ERC20 tokens for ETH would require users to grant a necessary allowance.

The account abstraction protocol by itself is generic and allows both accounts and paymasters to implement arbitrary interactions. However, the code of default accounts (EOAs) is constant, but we still want them to be able to participate in the ecosystem of custom accounts and paymasters. That's why we have standardized the paymasterInput field of the transaction to cover the most common uses-cases of the paymaster feature.

Your accounts are free to implement or not implement the support for these flows. However, this is highly encouraged to keep the interface the same for both EOAs and custom accounts.

General Paymaster Flow

This flow is used when the paymaster does not require any preliminary actions from the user:

The paymasterInput field must be encoded as a call to a function with the following interface:

function general(bytes calldata data);

For EOA accounts, this input is typically non-functional, but paymasters can interpret the data as needed.

Approval-Based Paymaster Flow

This flow is essential when a user must set a token allowance for the paymaster. The paymasterInput field must be encoded as a call to a function with the following signature:

function approvalBased(
    address _token,
    uint256 _minAllowance,
    bytes calldata _innerInput
);

The EOA will ensure that the allowance of the _token towards the paymaster is set to at least _minAllowance. The _innerInput param is an additional payload that can be sent to the paymaster to implement any logic (e.g. an additional signature or key that can be validated by the paymaster).

If you are developing a paymaster, you should not trust the transaction sender to behave honestly (e.g. provide the required allowance with the approvalBased flow). These flows serve mostly as instructions to EOAs and the requirements should always be double-checked by the paymaster.

Testnet paymaster

To ensure users experience paymasters on testnet, as well as keep supporting paying fees in ERC20 tokens, the Matter Labs team provides the testnet paymaster, that enables paying fees in ERC20 token at a 1:1 exchange rate with ETH (i.e. one unit of this token is equal to 1 wei of ETH).

The paymaster supports only the approval based paymaster flow and requires that the token param is equal to the token being swapped and minAllowance to equal to least tx.maxFeePerGas * tx.gasLimit. In addition, the testnet paymaster does not make use of the _innerInput parameter, so nothing should be provided (empty bytes).

Estimating Gas When Interacting with a Paymaster

Interacting with a paymaster generally consumes more gas than a standard transaction due to additional computations and operations. The primary factors contributing to this increased gas usage are:

  1. Internal Computations: These include the operations within the paymaster's validateAndPayForPaymasterTransaction and postTransaction.
  2. Funds Transfer: The gas consumed when a paymaster sends funds to the bootloader.
  3. ERC20 Token Allowance Management: Optionally, if the user compensates the paymaster with an ERC20 token, managing the token's allowance consumes additional gas.
  • The gas for internal computations is usually minimal, depending on the specific paymaster's implementation.
  • The cost of transferring funds is comparable to what users might pay for similar transactions independently.
  • Managing ERC20 allowances can significantly impact gas usage, particularly if it's the first time the user is setting an allowance. This process might require publishing a 32-byte storage key identifier, potentially using up to 400k gas at a 50 gwei L1 gas price. Notably, while the transactional flow often zeroes out the storage slot at execution's end (hence "grant X allowance + paymaster spends all allowance"), the initial cost is pre-charged during execution. Only if the slot is zeroed at the end of the transaction will the user be refunded.

Importance of Accurate Gas Estimation

Accurate gas estimation is crucial, especially for operations involving extensive pubdata, like writing to storage. You should include the necessary paymasterInput during estimation to ensure the paymaster's involvement is accurately accounted for. The code snippet below, from the Custom Paymaster Tutorial, demonstrates how to perform this estimation:

const gasLimit = await erc20.estimateGas.mint(wallet.address, 5, {
  customData: {
    gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT,
    paymasterParams: paymasterParams,
  },
});

Here, paymasterParams includes both the address of the paymaster and its input. However, paymasterInput often contains parameters that are difficult to predict ahead of time, such as the exact amount of tokens required by the user.

Additionally, paymasters may need to verify pricing data or conversion rates, possibly requiring a server-side signature.

Handling Complex Dependencies

Complex dependencies, such as those involving signatures that depend on transaction content, pose challenges:

  • Returning a magic = 0 from validateAndPayForPaymasterTransaction can simulate the gas consumption of a valid signature verification. This ensures that, although the transaction would fail on mainnet due to magic = 0, the correct gas amount can still be estimated.
  • Gas estimation is essentially a binary search for the lowest gas amount that prevents transaction failure. If validation consistently fails, so will the gas estimation, as the system will continuously attempt to increase the gas limit.

Strategies for Providing Allowance Estimates

  1. Rough Estimation: If you have a general idea of the funds involved, use it for the estimation. Minor differences won't typically cause transaction failure due to the buffer already included in our estimates. However, discrepancies can occur if the user's balance changes unexpectedly between estimation and transaction execution.
  2. Separate Estimation for Allowance Setting: Alternatively, estimate the gas for a transaction where the user sets the allowance separately. Add this estimate to the original transaction's estimated cost. This approach accounts for nonce changes and general validation logic but may introduce significant overhead.

Each method has its pros and cons, and choosing the right approach depends on the specific circumstances of the transaction and the paymaster's requirements.


Made with ❤️ by the ZKsync Community