Estimate gas costs for UserOperations with Para’s AA infrastructure before execution.

Prerequisites

You need a deployed smart account to estimate gas for operations.

Create Smart Account

Gas Components

UserOperations have three gas components:

  • callGasLimit: Gas for executing the main operation
  • verificationGasLimit: Gas for signature verification and account deployment
  • preVerificationGas: Gas for bundler overhead and L1 data costs (on L2s)

Estimate UserOp Gas

import { encodeFunctionData, parseAbi } from "viem";

async function estimateGas(
  client: any,
  operations: Array<{
    target: string;
    data?: string;
    value?: bigint;
  }>
) {
  try {
    const estimation = await client.estimateUserOperationGas({
      uo: operations.map(op => ({
        target: op.target,
        data: op.data || "0x",
        value: op.value || 0n
      }))
    });
    
    console.log("Gas Estimation:");
    console.log("- Call Gas Limit:", estimation.callGasLimit);
    console.log("- Verification Gas Limit:", estimation.verificationGasLimit);
    console.log("- Pre-verification Gas:", estimation.preVerificationGas);
    
    const totalGas = BigInt(estimation.callGasLimit) + 
                    BigInt(estimation.verificationGasLimit) + 
                    BigInt(estimation.preVerificationGas);
    
    console.log("Total Gas:", totalGas.toString());
    
    return estimation;
  } catch (error) {
    console.error("Gas estimation failed:", error);
    throw error;
  }
}

Calculate Gas Costs

import { formatEther } from "viem";

async function calculateGasCost(
  client: any,
  operations: any[]
) {
  const estimation = await client.estimateUserOperationGas({ uo: operations });
  
  const fees = await client.getUserOperationGasPrice();
  
  const totalGasLimit = BigInt(estimation.callGasLimit) + 
                       BigInt(estimation.verificationGasLimit) + 
                       BigInt(estimation.preVerificationGas);
  
  const maxCost = totalGasLimit * BigInt(fees.standard.maxFeePerGas);
  
  console.log("Gas Price (Gwei):", fees.standard.maxFeePerGas / 1e9);
  console.log("Max Cost (ETH):", formatEther(maxCost));
  
  return {
    gasEstimation: estimation,
    gasPrices: fees,
    maxCost: formatEther(maxCost),
    maxCostWei: maxCost
  };
}

L2 Gas Estimation

import { formatEther } from "viem";

async function estimateL2Gas(
  client: any,
  operations: any[]
) {
  const estimation = await client.estimateUserOperationGas({ 
    uo: operations 
  });
  
  console.log("L2 Gas Estimation:");
  console.log("- Execution Gas:", estimation.callGasLimit);
  console.log("- L1 Data Gas:", estimation.preVerificationGas);
  
  const l1GasWarning = BigInt(estimation.preVerificationGas) > 1000000n;
  
  if (l1GasWarning) {
    console.warn("⚠️  High L1 data costs detected!");
    console.warn("Consider batching operations to amortize L1 costs");
  }
  
  const bufferedPreVerificationGas = 
    (BigInt(estimation.preVerificationGas) * 125n) / 100n;
  
  return {
    ...estimation,
    preVerificationGas: bufferedPreVerificationGas.toString(),
    l1DataCost: estimation.preVerificationGas,
    hasHighL1Cost: l1GasWarning
  };
}

Override Gas Values

async function sendWithGasOverrides(
  client: any,
  operations: any[]
) {
  const estimation = await client.estimateUserOperationGas({ uo: operations });
  
  const bufferedCallGasLimit = 
    (BigInt(estimation.callGasLimit) * 120n) / 100n;
  
  const { hash } = await client.sendUserOperation({
    uo: operations,
    overrides: {
      callGasLimit: bufferedCallGasLimit,
      verificationGasLimit: BigInt(estimation.verificationGasLimit),
      preVerificationGas: BigInt(estimation.preVerificationGas),
      maxFeePerGas: await client.getGasPrice() * 2n,
      maxPriorityFeePerGas: 2000000000n
    }
  });
  
  console.log("UserOp sent with gas overrides:", hash);
  
  return hash;
}

Next Steps