Skip to main content

GasEstimate

GasEstimate represents the estimated gas required for a transaction, typically returned by eth_estimateGas RPC method. Always add buffer (20-30%) before using as gasLimit.

Type Definition

type GasEstimateType = bigint & { readonly [brand]: "GasEstimate" };
Branded bigint representing estimated gas (always non-negative).

Gas Estimation Flow

1. eth_estimateGas → minimum gas needed
2. Add buffer (20-30%) → account for variability
3. Set as gasLimit → transaction max gas
4. Execute → actual gasUsed ≤ gasLimit
5. Refund → (gasLimit - gasUsed) returned

API

Constructors

from(value)

Create GasEstimate from number, bigint, or string.
import { GasEstimate } from '@tevm/primitives';

// From eth_estimateGas response
const estimate = GasEstimate.from(rpcEstimate);

// From bigint
const est = GasEstimate.from(100_000n);

// From number
const est2 = GasEstimate.from(100000);

// From hex string
const est3 = GasEstimate.from("0x186a0");
Throws: InvalidFormatError if value is negative.

Conversions

toNumber(estimate)

Convert to number.
const estimate = GasEstimate.from(100_000n);
GasEstimate.toNumber(estimate); // 100000

toBigInt(estimate)

Convert to bigint (identity operation).
const estimate = GasEstimate.from(100_000n);
GasEstimate.toBigInt(estimate); // 100000n

toHex(estimate)

Convert to hex string.
const estimate = GasEstimate.from(100_000n);
GasEstimate.toHex(estimate); // "0x186a0"

Comparisons

equals(est1, est2)

Check equality.
GasEstimate.equals(100_000n, 100_000n); // true
GasEstimate.equals(100_000n, 120_000n); // false

compare(est1, est2)

Compare values (-1, 0, 1).
GasEstimate.compare(100_000n, 120_000n); // -1
GasEstimate.compare(100_000n, 100_000n); // 0
GasEstimate.compare(120_000n, 100_000n); // 1

Utilities

withBuffer(estimate, percentage)

Add percentage buffer to estimate.
const estimate = GasEstimate.from(100_000n);

// Add 20% buffer (recommended)
const buffered = GasEstimate.withBuffer(estimate, 20);
// 120,000n

// Add 30% buffer (conservative)
const safe = GasEstimate.withBuffer(estimate, 30);
// 130,000n
Recommended buffers:
  • Standard: 20-25%
  • Conservative: 30-40%
  • Network congestion: 50%+

toGasLimit(estimate)

Convert to gas limit (typically after adding buffer).
const estimate = GasEstimate.from(100_000n);
const withBuffer = GasEstimate.withBuffer(estimate, 25);
const gasLimit = GasEstimate.toGasLimit(withBuffer);
// 125,000n - ready to use as transaction gasLimit

Usage Examples

Basic Estimation

import { GasEstimate } from '@tevm/primitives';

// Get estimate from RPC
const estimate = await provider.estimateGas({
  to: '0x...',
  data: '0x...',
});

const gasEstimate = GasEstimate.from(estimate);
console.log(`Estimated gas: ${GasEstimate.toNumber(gasEstimate)}`);

Add Buffer and Send Transaction

import { GasEstimate } from '@tevm/primitives';

// Estimate gas
const rawEstimate = await provider.estimateGas(tx);
const estimate = GasEstimate.from(rawEstimate);

// Add 25% buffer for safety
const withBuffer = GasEstimate.withBuffer(estimate, 25);
const gasLimit = GasEstimate.toGasLimit(withBuffer);

// Send transaction with buffered gas limit
const signedTx = await wallet.signTransaction({
  ...tx,
  gasLimit,
});

await provider.sendTransaction(signedTx);

Compare Estimation Strategies

import { GasEstimate } from '@tevm/primitives';

const estimate = GasEstimate.from(100_000n);

const strategies = [
  { name: 'Standard', buffer: 20 },
  { name: 'Conservative', buffer: 30 },
  { name: 'Very Safe', buffer: 50 },
];

for (const { name, buffer } of strategies) {
  const buffered = GasEstimate.withBuffer(estimate, buffer);
  const limit = GasEstimate.toGasLimit(buffered);
  console.log(`${name}: ${limit} gas`);
}
// Standard: 120000 gas
// Conservative: 130000 gas
// Very Safe: 150000 gas

Handle Network Congestion

import { GasEstimate } from '@tevm/primitives';

async function estimateWithCongestion(tx) {
  const baseEstimate = await provider.estimateGas(tx);
  const estimate = GasEstimate.from(baseEstimate);

  // Check network congestion
  const block = await provider.getBlock('latest');
  const utilization = Number(block.gasUsed) / Number(block.gasLimit);

  // Adjust buffer based on congestion
  let buffer = 20; // Base 20%
  if (utilization > 0.9) buffer = 50; // High congestion
  else if (utilization > 0.7) buffer = 35; // Medium congestion

  const withBuffer = GasEstimate.withBuffer(estimate, buffer);
  return GasEstimate.toGasLimit(withBuffer);
}

Why Add Buffer?

eth_estimateGas returns the minimum gas needed under ideal conditions:
  1. State changes: Between estimation and execution, blockchain state may change
  2. Gas costs: Hard forks can change opcode gas costs
  3. Execution paths: Conditional logic may take different paths
  4. Rounding: EVM operations round up, estimation may round down
Without buffer: Transaction may fail with “out of gas” error. With buffer: Transaction succeeds, excess gas refunded.

Estimation Strategies

Standard (20-25%)

Good for:
  • Simple transfers
  • Known contract calls
  • Stable network conditions
const buffered = GasEstimate.withBuffer(estimate, 20);

Conservative (30-40%)

Good for:
  • Complex contract interactions
  • First-time contract calls
  • Unknown execution paths
const buffered = GasEstimate.withBuffer(estimate, 35);

Very Safe (50%+)

Good for:
  • Network congestion
  • Critical transactions
  • Maximum safety needed
const buffered = GasEstimate.withBuffer(estimate, 50);

Common Estimates

OperationTypical Estimate
ETH transfer21,000
ERC20 transfer50,000-65,000
Uniswap swap120,000-180,000
NFT mint80,000-150,000
Contract deployVaries widely

EIPs

  • EIP-150: Gas cost changes (1/64th rule)
  • EIP-2929: Cold/warm storage access costs
  • EIP-3529: Refund reduction (doesn’t affect estimation)

See Also