Documentation Index
Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
Use this file to discover all available pages before exploring further.
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
| Parameter | Type | Description |
|---|
calls | BatchCall[] | Array of calls to execute (single or multiple) |
calls[].to | Hex | The recipient address for this call |
calls[].value | bigint | The value to send in wei for this call |
calls[].data | Hex (optional) | The transaction data for this call |
walletAccount | EvmWalletAccount | The 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
React
Show the gas estimate to the user before they confirm the transaction:
import { estimateUserOperationGas, sendUserOperation } from '@dynamic-labs-sdk/zerodev';
import { isEvmWalletAccount } from '@dynamic-labs-sdk/evm';
import { useWalletAccounts } from '@dynamic-labs-sdk/react-hooks';
import { useState } from 'react';
import { parseEther, formatEther } from 'viem';
function GasEstimateFlow({ recipientAddress }) {
const walletAccounts = useWalletAccounts();
const walletAccount = walletAccounts.find(isEvmWalletAccount);
const [gasEstimate, setGasEstimate] = useState('');
const [confirmed, setConfirmed] = useState(false);
const calls = [{ to: recipientAddress, value: parseEther('0.1'), data: '0x' as const }];
const handleEstimate = async () => {
if (!walletAccount) return;
const gas = await estimateUserOperationGas({ walletAccount, calls });
if (gas) setGasEstimate(formatEther(gas));
};
const handleSend = async () => {
if (!walletAccount) return;
await sendUserOperation({ walletAccount, calls });
setConfirmed(true);
};
return (
<div>
<button onClick={handleEstimate} disabled={!walletAccount}>Estimate Gas</button>
{gasEstimate && (
<div>
<p>Estimated gas: {gasEstimate} ETH</p>
<button onClick={handleSend}>Confirm & Send</button>
</div>
)}
{confirmed && <p>Transaction sent!</p>}
</div>
);
}