For AI agents: a documentation index is available at /llms.txt. A markdown version of this page is available at the same URL with .md appended (or via Accept: text/markdown).
Skip to main content

AA21 didn't pay prefund

The EntryPoint contract reverts with AA21 didn't pay prefund when a smart accountMetaMask smart account A smart contract account created using the Smart Accounts Kit that supports programmable behavior, flexible signing options, and ERC-7710 delegations. doesn't have enough native token balance to cover the gas cost of the user operationUser operation A pseudo-transaction object defined by ERC-4337 that describes what a smart account should execute. User operations are submitted to the alternate mempool managed by bundlers..

Before executing a user operation, the EntryPoint requires the sender account to prefund the expected gas cost. If the account's balance is lower than the required prefund, the EntryPoint reverts the operation.

Solution​

Fund the smart account​

Fund the smart account with enough native tokens to cover the required prefund. Use Viem's estimateUserOperationGas to get the gas estimates from your bundlerBundler An ERC-4337 component that manages the alternate mempool: it collects user operations from smart accounts, packages them, and submits them to the network., then calculate the required prefund based on the EntryPoint version.

import { formatEther } from 'viem'

const gasEstimate = await bundlerClient.estimateUserOperationGas({
account: smartAccount,
calls: [{ to: '0x...', value: 0n }],
})

const { maxFeePerGas } = await publicClient.estimateFeesPerGas()

const requiredGas =
gasEstimate.verificationGasLimit +
gasEstimate.callGasLimit +
(gasEstimate.paymasterVerificationGasLimit ?? 0n) +
(gasEstimate.paymasterPostOpGasLimit ?? 0n) +
gasEstimate.preVerificationGas

const requiredPrefund = requiredGas * maxFeePerGas

const balance = await publicClient.getBalance({
address: smartAccount.address,
})

if (balance < requiredPrefund) {
console.log(
`Insufficient balance: account has ${formatEther(balance)} ETH, ` +
`but needs ${formatEther(requiredPrefund)} ETH`
)
}

Use a paymaster​

You can use a paymasterPaymaster A service that pays for user operations on behalf of a smart account. to sponsor the gas fees for the smart account, so the account doesn't need to hold native tokens. For more information about configuring a paymaster, see Send a gasless transaction.