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
- Alchemy
- ZeroDev
- Biconomy
- Pimlico
- Safe
Copy
Ask AI
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;
}
}
Copy
Ask AI
async function estimateGas(
kernelClient: any,
calls: Array<{
to: string;
data?: string;
value?: bigint;
}>
) {
try {
const userOp = await kernelClient.prepareUserOperationRequest({
callData: await kernelClient.account.encodeCalls(calls)
});
const estimation = await kernelClient.estimateUserOperationGas({
...userOp
});
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);
return estimation;
} catch (error) {
console.error("Gas estimation failed:", error);
throw error;
}
}
Copy
Ask AI
async function estimateGas(
smartAccount: any,
transactions: Array<{
to: string;
data?: string;
value?: string;
}>
) {
try {
const userOp = await smartAccount.buildUserOp(transactions);
const bundlerUrl = smartAccount.bundler.getBundlerUrl();
const chainId = await smartAccount.getChainId();
const response = await fetch(bundlerUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
method: "eth_estimateUserOperationGas",
params: [
userOp,
smartAccount.entryPointAddress
],
id: Date.now(),
jsonrpc: "2.0"
})
});
const result = await response.json();
const estimation = result.result;
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);
return estimation;
} catch (error) {
console.error("Gas estimation failed:", error);
throw error;
}
}
Copy
Ask AI
import { parseEther } from "viem";
async function estimateGas(
smartAccountClient: any,
calls: Array<{
to: string;
data?: string;
value?: bigint;
}>
) {
try {
const gas = await smartAccountClient.estimateUserOperationGas({
calls: calls.map(call => ({
to: call.to,
data: call.data || "0x",
value: call.value || 0n
}))
});
console.log("Gas Estimation:");
console.log("- Call Gas Limit:", gas.callGasLimit);
console.log("- Verification Gas Limit:", gas.verificationGasLimit);
console.log("- Pre-verification Gas:", gas.preVerificationGas);
if (gas.paymasterVerificationGasLimit) {
console.log("- Paymaster Verification Gas:", gas.paymasterVerificationGasLimit);
}
return gas;
} catch (error) {
console.error("Gas estimation failed:", error);
throw error;
}
}
Copy
Ask AI
async function estimateGas(
safe4337Pack: any,
transactions: Array<{
to: string;
data: string;
value: string;
}>
) {
try {
const safeTransaction = await safe4337Pack.createTransaction({
transactions
});
const estimation = await safe4337Pack.estimateSafeTransaction(
safeTransaction
);
console.log("Safe Gas Estimation:");
console.log("- Safe Operation:", estimation.safeTxGas);
console.log("- Base Gas:", estimation.baseGas);
console.log("- Data Gas:", estimation.dataGas);
const totalGas = BigInt(estimation.safeTxGas) +
BigInt(estimation.baseGas) +
BigInt(estimation.dataGas);
console.log("Total Gas Estimate:", totalGas.toString());
return estimation;
} catch (error) {
console.error("Gas estimation failed:", error);
throw error;
}
}
Calculate Gas Costs
- Alchemy
- ZeroDev
- Biconomy
Copy
Ask AI
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
};
}
Copy
Ask AI
import { formatEther } from "viem";
async function calculateGasCost(
kernelClient: any,
publicClient: any,
calls: any[]
) {
const userOp = await kernelClient.prepareUserOperationRequest({
callData: await kernelClient.account.encodeCalls(calls)
});
const estimation = await kernelClient.estimateUserOperationGas(userOp);
const { maxFeePerGas } = await publicClient.estimateFeesPerGas();
const totalGasLimit = BigInt(estimation.callGasLimit) +
BigInt(estimation.verificationGasLimit) +
BigInt(estimation.preVerificationGas);
const maxCost = totalGasLimit * maxFeePerGas;
console.log("Gas Price (Gwei):", Number(maxFeePerGas) / 1e9);
console.log("Max Cost (ETH):", formatEther(maxCost));
return {
gasEstimation: estimation,
maxFeePerGas,
maxCost: formatEther(maxCost),
maxCostWei: maxCost
};
}
Copy
Ask AI
import { ethers } from "ethers";
async function calculateGasCost(
smartAccount: any,
provider: ethers.providers.Provider,
transactions: any[]
) {
const userOp = await smartAccount.buildUserOp(transactions);
const bundlerUrl = smartAccount.bundler.getBundlerUrl();
const response = await fetch(bundlerUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
method: "eth_estimateUserOperationGas",
params: [userOp, smartAccount.entryPointAddress],
id: Date.now(),
jsonrpc: "2.0"
})
});
const result = await response.json();
const estimation = result.result;
const feeData = await provider.getFeeData();
const totalGasLimit = BigInt(estimation.callGasLimit) +
BigInt(estimation.verificationGasLimit) +
BigInt(estimation.preVerificationGas);
const maxCost = totalGasLimit * BigInt(feeData.maxFeePerGas.toString());
return {
gasEstimation: estimation,
maxFeePerGas: feeData.maxFeePerGas,
maxCost: ethers.utils.formatEther(maxCost),
maxCostWei: maxCost
};
}
L2 Gas Estimation
- Optimism/Base
- Arbitrum
Copy
Ask AI
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
};
}
Copy
Ask AI
async function estimateArbitrumGas(
client: any,
operations: any[]
) {
const estimation = await client.estimateUserOperationGas({
uo: operations,
stateOverride: {
[client.account.address]: {
balance: "0xFFFFFFFFFFFFFFFF"
}
}
});
console.log("Arbitrum Gas Estimation:");
console.log("- L2 Gas Limit:", estimation.callGasLimit);
console.log("- L1 Calldata Gas:", estimation.preVerificationGas);
const l2GasPrice = await client.getGasPrice();
const l1GasPrice = await client.getL1GasPrice();
const l2Cost = BigInt(estimation.callGasLimit) * l2GasPrice;
const l1Cost = BigInt(estimation.preVerificationGas) * l1GasPrice;
console.log("L2 Cost:", formatEther(l2Cost));
console.log("L1 Cost:", formatEther(l1Cost));
console.log("Total Cost:", formatEther(l2Cost + l1Cost));
return {
gasEstimation: estimation,
l2Cost: formatEther(l2Cost),
l1Cost: formatEther(l1Cost),
totalCost: formatEther(l2Cost + l1Cost)
};
}
Override Gas Values
- Alchemy
- ZeroDev
Copy
Ask AI
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;
}
Copy
Ask AI
async function sendWithGasOverrides(
kernelClient: any,
calls: any[]
) {
const userOp = await kernelClient.prepareUserOperationRequest({
callData: await kernelClient.account.encodeCalls(calls)
});
const estimation = await kernelClient.estimateUserOperationGas(userOp);
const userOpHash = await kernelClient.sendUserOperation({
...userOp,
callGasLimit: (BigInt(estimation.callGasLimit) * 110n) / 100n,
verificationGasLimit: BigInt(estimation.verificationGasLimit),
preVerificationGas: (BigInt(estimation.preVerificationGas) * 125n) / 100n,
maxFeePerGas: userOp.maxFeePerGas * 2n,
maxPriorityFeePerGas: 2000000000n
});
console.log("UserOp sent with overrides:", userOpHash);
return userOpHash;
}