Skip to main content

estimateUserOperationGas

Estimates the total gas cost for a user operation with one or more calls. Works for both single transactions and batch transactions. The estimation includes all gas components: call gas, verification gas, and pre-verification gas.

Usage

import { estimateUserOperationGas } from "@dynamic-labs-sdk/zerodev";
import { isEvmWalletAccount } from "@dynamic-labs-sdk/evm";
import { getPrimaryWalletAccount } from "@dynamic-labs-sdk/client";
import { parseEther, formatEther } from "viem";

const walletAccount = getPrimaryWalletAccount();

if (walletAccount && isEvmWalletAccount(walletAccount)) {
  const estimatedGas = await estimateUserOperationGas({
    walletAccount,
    calls: [
      {
        to: recipientAddress,
        value: parseEther("0.01"),
        data: "0x",
      },
    ],
  });

  if (estimatedGas) {
    console.log(`Estimated gas cost: ${formatEther(estimatedGas)} ETH`);
  } else {
    console.log("Failed to estimate gas");
  }
}

Parameters

ParameterTypeDescription
callsBatchCall[]Array of calls to execute (single or multiple)
calls[].toHexThe recipient address for this call
calls[].valuebigintThe value to send in wei for this call
calls[].dataHex (optional)The transaction data for this call
walletAccountEvmWalletAccountThe wallet account that will execute the operation

Returns

Promise<bigint | null> - Returns the estimated gas cost in wei, or null if estimation fails. The gas estimate includes:
  • Call Gas Limit: Gas for executing the calls
  • Verification Gas Limit: Gas for validating the UserOperation
  • Pre-verification Gas: Fixed gas overhead

Examples

Single transaction

const estimatedGas = await estimateUserOperationGas({
  walletAccount,
  calls: [
    {
      to: "0x...",
      value: parseEther("0.1"),
    },
  ],
});

if (estimatedGas) {
  console.log(`Gas estimate: ${estimatedGas} wei`);
}

Batch transaction

const estimatedGas = await estimateUserOperationGas({
  walletAccount,
  calls: [
    { to: "0xRecipient1...", value: parseEther("0.1") },
    { to: "0xRecipient2...", value: parseEther("0.2") },
    { to: "0xRecipient3...", value: parseEther("0.3") },
  ],
});

if (estimatedGas) {
  console.log(`Batch gas estimate: ${formatEther(estimatedGas)} ETH`);
}

Estimate before sending

import {
  estimateUserOperationGas,
  sendUserOperation
} from "@dynamic-labs-sdk/zerodev";

const calls = [
  { to: "0x...", value: parseEther("0.1") },
  { to: "0x...", value: parseEther("0.2") },
];

// Estimate gas first
const estimatedGas = await estimateUserOperationGas({
  walletAccount,
  calls,
});

if (estimatedGas) {
  const gasInEth = formatEther(estimatedGas);
  console.log(`This operation will cost approximately ${gasInEth} ETH`);

  // User confirms, then send
  const receipt = await sendUserOperation({
    walletAccount,
    calls,
  });
  console.log("Transaction sent:", receipt.userOpHash);
}

With contract interaction

import { encodeFunctionData } from "viem";

const estimatedGas = await estimateUserOperationGas({
  walletAccount,
  calls: [
    {
      to: tokenAddress,
      value: 0n,
      data: encodeFunctionData({
        abi: erc20Abi,
        functionName: "transfer",
        args: [recipientAddress, parseEther("100")],
      }),
    },
  ],
});

Notes

  • Gas estimation creates a kernel client without sponsorship to get accurate unsponsored gas costs
  • Returns null if estimation fails (e.g., insufficient funds, invalid call)
  • Batch transactions may save gas compared to individual transactions due to shared validation costs
  • The actual gas used may differ slightly from the estimate