Error: account validation failed: AA21 didn't pay prefund

Getting this error while making a gasless txn for account abstraction.

1 Like

based on the limited information to my guess ,this error usually occurs in two situations

  1. The contract on which you are executing the transaction is not whitelisted, if the contract is infact whitelisted then the function being called in the transaction is not whitelisted.
  2. Your paymaster is not initialized correctly
1 Like

Hi, got the same issue today. error Error: account validation failed: AA21 didn't pay prefund
I made sure that contract and the particular function is whitelisted.
How to know whether the paymaster init correctly. could there be anyother issue, like node error?

Hi, did this resolve?

1 Like

Hi, facing the same error. Anyone found the solution for this?

1 Like

Hi,

This error pops up when

  1. If you are not using the paymaster

    The refund is expected from the wallet but the wallet doesn’t have any funds.
    To resolve this make sure you have funded the smart wallet.

  2. If you are using the paymaster

    Make sure of the following things -

    1. You have whitelisted the contracts
    2. You are using the latest version of sdk and correct dashboard.
      If this also is in place please send us the userOp endpoint from the network tab (front end) or if it is a backend integration - share logs after doing export BICONOMY_SDK_DEBUG = true in the terminal

hi , i have properly followed the docs but i’m still getting this error:

contract and functions i’m calling , both are whitelisted:

import { PaymasterMode } from "@biconomy/paymaster";
import { ethers } from "ethers";
import SwapData from "../assets/data.js";
import AbstractSwap from "../abi/AbstractSwap.json";


async function BiconomyERC20Pay(smartAccount,tokenIn,amount,flag){

  const provider = new ethers.providers.Web3Provider(window.ethereum);

  const contract = new ethers.Contract(
    SwapData.SwapContract,
    AbstractSwap,
    provider
  );

  // use the ethers populateTransaction method to create a raw transaction
  const minTx = await contract.populateTransaction.SwapNovice(
    tokenIn,
    amount,
    flag
  );

  console.log("minTx",minTx);
  
  const tx1 = {
    to: SwapData.SwapContract,
    data: minTx.data,
  };
  let userOp = await smartAccount.buildUserOp([tx1]);

  console.log("userOp",userOp);

  const biconomyPaymaster = smartAccount.paymaster;
  
  const feeQuotesResponse =
        await biconomyPaymaster.getPaymasterFeeQuotesOrData(userOp, {
            mode: PaymasterMode.ERC20,
            tokenList: ["0xda5289fcaaf71d52a80a254da614a192b693e977"],
        });

    const feeQuotes = feeQuotesResponse.feeQuotes;
    const spender = feeQuotesResponse.tokenPaymasterAddress || "";
    const usdcFeeQuotes = feeQuotes[0];

    console.log("usdcFeeQuotes",usdcFeeQuotes);

   let finalUserOp = await smartAccount.buildTokenPaymasterUserOp(userOp, {
        feeQuote: usdcFeeQuotes,
        spender: spender,
        maxApproval: false,
    });

    console.log("finalUserOp",finalUserOp);


    let paymasterServiceData = {
      mode: PaymasterMode.ERC20,
      feeTokenAddress: usdcFeeQuotes.tokenAddress,
      calculateGasLimits: true, // Always recommended and especially when using token paymaster
    };

    console.log("paymasterServiceData",paymasterServiceData);

    try {
      const paymasterAndDataWithLimits =
        await biconomyPaymaster.getPaymasterAndData(
          finalUserOp,
          paymasterServiceData
        );
      finalUserOp.paymasterAndData =
        paymasterAndDataWithLimits.paymasterAndData;
      if (
        paymasterAndDataWithLimits.callGasLimit &&
        paymasterAndDataWithLimits.verificationGasLimit &&
        paymasterAndDataWithLimits.preVerificationGas
      ) {
        // Returned gas limits must be replaced in your op as you update paymasterAndData.
        // Because these are the limits paymaster service signed on to generate paymasterAndData
        // If you receive AA34 error check here..

        finalUserOp.callGasLimit = paymasterAndDataWithLimits.callGasLimit;
        finalUserOp.verificationGasLimit =
          paymasterAndDataWithLimits.verificationGasLimit;
        finalUserOp.preVerificationGas =
          paymasterAndDataWithLimits.preVerificationGas;
      }
    } catch (e) {
      console.log("error received ", e);
    }


    
const userOpResponse = await smartAccount.sendUserOp(userOp);
console.log("userOpHash", userOpResponse);
const { receipt } = await userOpResponse.wait(1);
console.log("txHash", receipt.transactionHash);

return receipt.transactionHash;



}


export default BiconomyERC20Pay;
1 Like

Hi, You need to config Paymaster Sponsor or send Native token to smart account address.

When initializing your smart account, you can get smart account address with biconomyAccount.getAccountAddress()

Send Native token like MATIC or ETHER to smart account address.

Your smart account address needs native tokens even before smart account to be deployed if you don’t config Paymaster Sponsor.