Skip to main content

GasCosts

Constants for gas costs of EVM operations, based on Yellow Paper Appendix G and various EIPs.

Constants

Transaction Costs

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

GAS_COSTS.TRANSACTION      // 21000n - Base transaction cost
GAS_COSTS.CREATE           // 32000n - Contract creation
GAS_COSTS.CALL_VALUE       // 9000n - Non-zero value transfer
GAS_COSTS.CALL_STIPEND     // 2300n - Stipend for call with value

Storage Operations

GAS_COSTS.SLOAD            // 2100n - Cold SLOAD (EIP-2929)
GAS_COSTS.SLOAD_WARM       // 100n - Warm SLOAD
GAS_COSTS.SSTORE_SET       // 20000n - Zero to non-zero
GAS_COSTS.SSTORE_RESET     // 5000n - Non-zero to non-zero
GAS_COSTS.SSTORE_CLEAR     // 15000n - Refund (pre-London)

Account Access (EIP-2929)

GAS_COSTS.BALANCE          // 2600n - Cold BALANCE
GAS_COSTS.EXTCODECOPY      // 2600n - Cold EXTCODECOPY
GAS_COSTS.COLD_ACCOUNT_ACCESS  // 2600n - Cold account
GAS_COSTS.WARM_STORAGE_READ    // 100n - Warm access

Logging

GAS_COSTS.LOG              // 375n - LOG0 base
GAS_COSTS.LOG_TOPIC        // 375n - Per topic
GAS_COSTS.LOG_DATA         // 8n - Per byte of data

Calldata

GAS_COSTS.CALLDATA_ZERO    // 4n - Zero byte
GAS_COSTS.CALLDATA_NONZERO // 16n - Non-zero byte

Memory & Copying

GAS_COSTS.MEMORY           // 3n - Per word expansion
GAS_COSTS.COPY             // 3n - Per word copy

Cryptographic Operations

GAS_COSTS.SHA3             // 30n - KECCAK256 base
GAS_COSTS.SHA3_WORD        // 6n - Per word
GAS_COSTS.BLOCKHASH        // 20n - BLOCKHASH opcode

Other Operations

GAS_COSTS.SELFDESTRUCT     // 5000n - SELFDESTRUCT
GAS_COSTS.CALL             // 100n - Base message call
GAS_COSTS.EXP              // 10n - EXP base
GAS_COSTS.EXP_BYTE         // 50n - EXP per byte
GAS_COSTS.JUMPDEST         // 1n - JUMPDEST

Opcode Cost Tiers

GAS_COSTS.BASE             // 2n - Most opcodes
GAS_COSTS.VERY_LOW         // 3n - ADD, SUB, etc
GAS_COSTS.LOW              // 5n - MUL, DIV, etc
GAS_COSTS.MID              // 8n - ADDMOD, MULMOD
GAS_COSTS.HIGH             // 10n - JUMPI

Block Limits

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

BLOCK_GAS_LIMITS.MAINNET   // 30_000_000n - Typical mainnet
BLOCK_GAS_LIMITS.MINIMUM   // 5000n - EIP-1559 minimum

Transaction Type Costs

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

TRANSACTION_COSTS.SIMPLE_TRANSFER  // 21000n
TRANSACTION_COSTS.ERC20_TRANSFER   // 65000n
TRANSACTION_COSTS.UNISWAP_SWAP     // 150000n
TRANSACTION_COSTS.CONTRACT_DEPLOY  // 32000n (base)

Usage Examples

Calculate Calldata Cost

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

function calculateCalldataCost(data: Uint8Array): bigint {
  let cost = 0n;
  for (const byte of data) {
    cost += byte === 0
      ? GAS_COSTS.CALLDATA_ZERO
      : GAS_COSTS.CALLDATA_NONZERO;
  }
  return cost;
}

const calldata = new Uint8Array([0x00, 0x01, 0x02]);
const cost = calculateCalldataCost(calldata);
// 4n + 16n + 16n = 36n

Calculate LOG Cost

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

function calculateLogCost(topics: number, dataBytes: number): bigint {
  const baseCost = GAS_COSTS.LOG;
  const topicCost = BigInt(topics) * GAS_COSTS.LOG_TOPIC;
  const dataCost = BigInt(dataBytes) * GAS_COSTS.LOG_DATA;
  return baseCost + topicCost + dataCost;
}

// LOG3 with 64 bytes of data
const cost = calculateLogCost(3, 64);
// 375n + (3 × 375n) + (64 × 8n) = 1887n

Estimate Transaction Base Cost

import { GAS_COSTS, TRANSACTION_COSTS } from '@tevm/primitives';

function estimateTransactionCost(
  calldata: Uint8Array,
  hasValue: boolean
): bigint {
  let cost = GAS_COSTS.TRANSACTION; // 21000n base

  // Add calldata cost
  for (const byte of calldata) {
    cost += byte === 0
      ? GAS_COSTS.CALLDATA_ZERO
      : GAS_COSTS.CALLDATA_NONZERO;
  }

  // Add value transfer cost
  if (hasValue) {
    cost += GAS_COSTS.CALL_VALUE;
  }

  return cost;
}

Compare Storage Operations

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

const operations = {
  'Set (0 → X)': GAS_COSTS.SSTORE_SET,
  'Reset (X → Y)': GAS_COSTS.SSTORE_RESET,
  'Clear (X → 0)': GAS_COSTS.SSTORE_RESET, // Cost to clear
  'Load (cold)': GAS_COSTS.SLOAD,
  'Load (warm)': GAS_COSTS.SLOAD_WARM,
};

for (const [op, cost] of Object.entries(operations)) {
  console.log(`${op}: ${cost} gas`);
}

EIP Changes

EIP-2929 (Berlin)

Cold vs warm access distinction:
// Pre-EIP-2929
SLOAD: 800 gas (always)

// Post-EIP-2929
SLOAD (cold): 2100 gas (first access)
SLOAD (warm): 100 gas (subsequent access)

EIP-3529 (London)

Refund reduction:
// Pre-EIP-3529
SSTORE clear refund: 15000 gas
SELFDESTRUCT refund: 24000 gas

// Post-EIP-3529
SSTORE clear refund: 15000 gas (capped at gasUsed/5)
SELFDESTRUCT refund: 0 gas

EIP-1559 (London)

Changed fee structure but not gas costs:
// Gas costs unchanged
// But introduced:
// - Base fee (burned)
// - Priority fee (to miner)
// - Max fee per gas

Cost Categories

Cheap Operations (≤ 10 gas)

  • Stack operations: PUSH, POP, DUP, SWAP
  • Arithmetic: ADD, SUB, MUL, DIV
  • Logic: AND, OR, XOR, NOT
  • Comparison: LT, GT, EQ

Medium Operations (10-100 gas)

  • SHA3/KECCAK256: 30 + 6 per word
  • BLOCKHASH: 20
  • Message calls (base): 100

Expensive Operations (100-2600 gas)

  • SLOAD (warm): 100
  • SLOAD (cold): 2100
  • Account access (cold): 2600

Very Expensive Operations (5000-20000 gas)

  • SSTORE (reset): 5000
  • SELFDESTRUCT: 5000
  • SSTORE (set): 20000

Transaction Base Costs (≥ 21000 gas)

  • Simple transfer: 21000
  • Contract creation: 32000+
  • Complex interactions: 50000-1000000+

Memory Costs

Memory expansion is quadratic:
const memoryCost = (words: bigint): bigint => {
  return (GAS_COSTS.MEMORY * words) + (words * words) / 512n;
};

memoryCost(10n);  // 30n + 0n = 30n
memoryCost(100n); // 300n + 19n = 319n
memoryCost(1000n); // 3000n + 1953n = 4953n

See Also