Skip to main content
Estimate gas for a transaction before sending
import { Transaction } from '@tevm/voltaire/Transaction';
import { Address } from '@tevm/voltaire/Address';
import { Hex } from '@tevm/voltaire/Hex';
import { Wei, Gwei, Ether } from '@tevm/voltaire/Denomination';

// RPC helper (using native fetch)
async function rpc(url: string, method: string, params: unknown[]) {
	const response = await fetch(url, {
		method: "POST",
		headers: { "Content-Type": "application/json" },
		body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
	});
	const json = await response.json();
	if (json.error) throw new Error(json.error.message);
	return json.result;
}

const RPC_URL = "https://eth.llamarpc.com";

// Create call object for gas estimation
const from = Address.from("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266");
const to = Address.from("0x70997970C51812dc3A010C7d01b50e0d17dc79C8");
const value = Wei.from(1_000_000_000_000_000_000n); // 1 ETH

const callObject = {
	from: Hex.fromBytes(from),
	to: Hex.fromBytes(to),
	value: Hex.fromNumber(Wei.toU256(value)),
	data: "0x", // No calldata for simple transfer
};

// Estimate gas using eth_estimateGas
const estimatedGasHex = await rpc(RPC_URL, "eth_estimateGas", [callObject]);
const estimatedGas = BigInt(estimatedGasHex);

// Add 20% buffer for safety
const gasWithBuffer = (estimatedGas * 120n) / 100n;

// Fetch current gas prices using eth_gasPrice and eth_maxPriorityFeePerGas
const [gasPriceHex, feeHistoryResult] = await Promise.all([
	rpc(RPC_URL, "eth_gasPrice", []),
	rpc(RPC_URL, "eth_feeHistory", [1, "latest", [50]]),
]);

// Parse gas price and base fee
const gasPrice = BigInt(gasPriceHex);
const baseFee = BigInt(feeHistoryResult.baseFeePerGas[0]);

// Calculate priority fee (tip) from fee history
const priorityFee = 2_000_000_000n; // 2 gwei default tip

// Calculate max fee per gas (base fee * 2 + priority fee for safety)
const maxFeePerGas = baseFee * 2n + priorityFee;
const maxPriorityFeePerGas = priorityFee;

// Calculate total cost in wei
const maxCostWei = Wei.from(gasWithBuffer * maxFeePerGas);
const maxCostGwei = Gwei.fromWei(maxCostWei);
const maxCostEther = Ether.fromWei(maxCostWei);

// Effective cost at current base fee
const effectiveCostWei = Wei.from(gasWithBuffer * (baseFee + priorityFee));

// Build the transaction with estimated values
const txParams = {
	type: Transaction.Type.EIP1559,
	chainId: 1n,
	nonce: 0n,
	maxPriorityFeePerGas,
	maxFeePerGas,
	gasLimit: gasWithBuffer,
	to,
	value: Wei.toU256(value),
	data: new Uint8Array(),
	accessList: [],
};

console.log("Gas Estimation Results:");
console.log(`  Estimated gas: ${estimatedGas}`);
console.log(`  Gas with buffer: ${gasWithBuffer}`);
console.log(`  Base fee: ${Gwei.fromWei(Wei.from(baseFee))} gwei`);
console.log(`  Priority fee: ${Gwei.fromWei(Wei.from(priorityFee))} gwei`);
console.log(`  Max fee per gas: ${Gwei.fromWei(Wei.from(maxFeePerGas))} gwei`);
console.log(`  Max cost: ${maxCostEther} ETH`);
This is a fully executable example. View the complete source with test assertions at examples/transactions/estimate-gas.ts.