Skip to main content

Try it Live

Run FeeMarket examples in the interactive playground

Fee Market Calculations

Transaction fee calculations and state transitions.

calculateTxFee

calculateTxFee(params: TxFeeParams): TxFee
Calculate EIP-1559 transaction fee breakdown. Parameters:
  • params.maxFeePerGas - Maximum fee per gas (wei)
  • params.maxPriorityFeePerGas - Maximum priority fee/tip (wei)
  • params.baseFee - Current block base fee (wei)
Returns: TxFee with effectiveGasPrice, priorityFee, baseFee Formula:
effectiveGasPrice = min(maxFeePerGas, baseFee + maxPriorityFeePerGas)
priorityFee = effectiveGasPrice - baseFee
Examples:
import * as FeeMarket from './FeeMarket.js';

// Full tip paid
const fee1 = FeeMarket.calculateTxFee({
  maxFeePerGas: 2_000_000_000n,        // 2 gwei max
  maxPriorityFeePerGas: 1_000_000_000n, // 1 gwei tip
  baseFee: 800_000_000n                 // 0.8 gwei base
});
// fee1.effectiveGasPrice === 1_800_000_000n (0.8 + 1.0)
// fee1.priorityFee === 1_000_000_000n (full tip)
// fee1.baseFee === 800_000_000n

// Tip capped by maxFee
const fee2 = FeeMarket.calculateTxFee({
  maxFeePerGas: 2_000_000_000n,
  maxPriorityFeePerGas: 1_500_000_000n, // Want 1.5 gwei tip
  baseFee: 1_800_000_000n               // 1.8 gwei base
});
// fee2.effectiveGasPrice === 2_000_000_000n (capped at maxFee)
// fee2.priorityFee === 200_000_000n (reduced tip: 2.0 - 1.8)
// fee2.baseFee === 1_800_000_000n

// No tip paid
const fee3 = FeeMarket.calculateTxFee({
  maxFeePerGas: 1_000_000_000n,
  maxPriorityFeePerGas: 100_000_000n,
  baseFee: 1_000_000_000n // maxFee === baseFee
});
// fee3.effectiveGasPrice === 1_000_000_000n
// fee3.priorityFee === 0n (no tip)
Total Cost:
const fee = FeeMarket.calculateTxFee(params);
const gasUsed = 21_000n; // Standard transfer

const totalCost = fee.effectiveGasPrice * gasUsed;
// totalCost in wei

const breakdown = {
  baseFee: fee.baseFee * gasUsed,
  priorityFee: fee.priorityFee * gasUsed,
  total: totalCost
};

calculateBlobTxFee

calculateBlobTxFee(params: BlobTxFeeParams): BlobTxFee
Calculate blob transaction fee (EIP-4844). Combines regular gas fee with blob gas fee. Parameters:
  • params.maxFeePerGas - Maximum fee per gas (wei)
  • params.maxPriorityFeePerGas - Maximum priority fee (wei)
  • params.baseFee - Current block base fee (wei)
  • params.maxFeePerBlobGas - Maximum blob gas fee (wei)
  • params.blobBaseFee - Current blob base fee (wei)
  • params.blobCount - Number of blobs (1-6)
Returns: BlobTxFee extending TxFee with blobGasPrice, totalBlobFee Formula:
// Regular gas (from calculateTxFee)
effectiveGasPrice = min(maxFeePerGas, baseFee + maxPriorityFeePerGas)
priorityFee = effectiveGasPrice - baseFee

// Blob gas
blobGasPrice = min(maxFeePerBlobGas, blobBaseFee)
totalBlobFee = blobGasPrice * BLOB_GAS_PER_BLOB * blobCount
Examples:
import * as FeeMarket from './FeeMarket.js';

// Standard blob transaction
const fee1 = FeeMarket.calculateBlobTxFee({
  maxFeePerGas: 2_000_000_000n,
  maxPriorityFeePerGas: 1_000_000_000n,
  baseFee: 800_000_000n,
  maxFeePerBlobGas: 10_000_000n,  // 10 wei/gas
  blobBaseFee: 5_000_000n,         // 5 wei/gas
  blobCount: 3n
});
// fee1.effectiveGasPrice === 1_800_000_000n
// fee1.priorityFee === 1_000_000_000n
// fee1.blobGasPrice === 5_000_000n (below maxFee)
// fee1.totalBlobFee === 1_966_080_000_000n (3 * 131072 * 5)

// Blob fee capped
const fee2 = FeeMarket.calculateBlobTxFee({
  maxFeePerGas: 2_000_000_000n,
  maxPriorityFeePerGas: 1_000_000_000n,
  baseFee: 800_000_000n,
  maxFeePerBlobGas: 3_000_000n,    // Lower max
  blobBaseFee: 5_000_000n,         // Higher actual
  blobCount: 1n
});
// fee2.blobGasPrice === 3_000_000n (capped at maxFee)
// fee2.totalBlobFee === 393_216_000_000n (1 * 131072 * 3)
Total Cost:
const fee = FeeMarket.calculateBlobTxFee(params);
const gasUsed = 100_000n; // Execution gas

const executionCost = fee.effectiveGasPrice * gasUsed;
const blobCost = fee.totalBlobFee;
const totalCost = executionCost + blobCost;

console.log(`Execution: ${FeeMarket.weiToGwei(executionCost)} gwei`);
console.log(`Blobs: ${FeeMarket.weiToGwei(blobCost)} gwei`);
console.log(`Total: ${FeeMarket.weiToGwei(totalCost)} gwei`);

canIncludeTx

canIncludeTx(params: TxFeeParams | BlobTxFeeParams): boolean
Check if transaction meets minimum fee requirements for inclusion. Parameters:
  • params - Transaction or blob transaction fee parameters
Returns: true if transaction can be included Validation:
  • Regular tx: maxFeePerGas >= baseFee
  • Blob tx: Above + maxFeePerBlobGas >= blobBaseFee
Examples:
import * as FeeMarket from './FeeMarket.js';

// Can include
const canInclude1 = FeeMarket.canIncludeTx({
  maxFeePerGas: 2_000_000_000n,
  maxPriorityFeePerGas: 1_000_000_000n,
  baseFee: 1_000_000_000n
});
// canInclude1 === true (2 gwei >= 1 gwei)

// Cannot include
const canInclude2 = FeeMarket.canIncludeTx({
  maxFeePerGas: 800_000_000n,        // Too low
  maxPriorityFeePerGas: 100_000_000n,
  baseFee: 1_000_000_000n
});
// canInclude2 === false (0.8 gwei < 1 gwei)

// Blob transaction
const canInclude3 = FeeMarket.canIncludeTx({
  maxFeePerGas: 2_000_000_000n,
  maxPriorityFeePerGas: 1_000_000_000n,
  baseFee: 1_000_000_000n,
  maxFeePerBlobGas: 10_000_000n,
  blobBaseFee: 5_000_000n,
  blobCount: 3n
});
// canInclude3 === true (both gas and blob fees sufficient)

// Blob fee too low
const canInclude4 = FeeMarket.canIncludeTx({
  maxFeePerGas: 2_000_000_000n,
  maxPriorityFeePerGas: 1_000_000_000n,
  baseFee: 1_000_000_000n,
  maxFeePerBlobGas: 3_000_000n,      // Too low
  blobBaseFee: 5_000_000n,
  blobCount: 3n
});
// canInclude4 === false (blob fee insufficient)
Usage:
const params = buildTxParams();

if (!FeeMarket.canIncludeTx(params)) {
  // Increase fees
  params.maxFeePerGas = baseFee + 1_000_000_000n; // Add 1 gwei buffer

  if ('maxFeePerBlobGas' in params) {
    params.maxFeePerBlobGas = blobBaseFee * 2n; // 2x buffer
  }
}

nextState

nextState(state: State): State
Calculate next block’s complete fee market state. Parameters:
  • state - Current block state
Returns: Next block’s state with updated fees and reset usage Updates:
  • baseFee - Calculated via BaseFee
  • excessBlobGas - Calculated via calculateExcessBlobGas
  • gasUsed - Reset to 0
  • blobGasUsed - Reset to 0
  • gasLimit - Unchanged
Examples:
import * as FeeMarket from './FeeMarket.js';

const currentState: FeeMarket.State = {
  gasUsed: 25_000_000n,   // 83% full (above target)
  gasLimit: 30_000_000n,
  baseFee: 1_000_000_000n,
  excessBlobGas: 0n,
  blobGasUsed: 524288n    // 4 blobs (above target)
};

const nextState = FeeMarket.nextState(currentState);
// nextState.gasUsed === 0n (reset)
// nextState.baseFee > 1_000_000_000n (increased, above gas target)
// nextState.excessBlobGas === 131072n (1 blob excess accumulated)
// nextState.blobGasUsed === 0n (reset)
// nextState.gasLimit === 30_000_000n (unchanged)
State method:
const nextState = FeeMarket.State.next.call(currentState);
// Same result
Multi-block projection:
let state = currentState;

// Simulate 10 blocks with constant usage
const blobGasUsed = 524288n; // 4 blobs per block
const gasUsed = 25_000_000n; // 83% full

for (let i = 0; i < 10; i++) {
  state = FeeMarket.nextState({
    ...state,
    gasUsed,
    blobGasUsed
  });

  console.log(`Block ${i + 1}:`);
  console.log(`  Base fee: ${FeeMarket.weiToGwei(state.baseFee)} gwei`);
  console.log(`  Excess blob gas: ${state.excessBlobGas}`);
}
// Fees compound over blocks

projectBaseFees

projectBaseFees(
  initialState: State,
  blocks: number,
  avgGasUsed: bigint,
  avgBlobGasUsed?: bigint
): bigint[]
Project future base fees over multiple blocks with constant utilization. Parameters:
  • initialState - Starting state
  • blocks - Number of blocks to project
  • avgGasUsed - Average gas used per block
  • avgBlobGasUsed - Average blob gas per block (optional, default 0)
Returns: Array of projected base fees (length = blocks) Examples:
import * as FeeMarket from './FeeMarket.js';

const state: FeeMarket.State = {
  gasUsed: 0n,
  gasLimit: 30_000_000n,
  baseFee: 1_000_000_000n, // 1 gwei
  excessBlobGas: 0n,
  blobGasUsed: 0n
};

// High utilization: fees rise
const risingFees = FeeMarket.projectBaseFees(
  state,
  10,          // 10 blocks
  25_000_000n, // 83% full (above target)
  524288n      // 4 blobs (above target)
);
// risingFees[0] > 1 gwei
// risingFees[9] >> risingFees[0] (compounding)

// At target: fees stable
const stableFees = FeeMarket.projectBaseFees(
  state,
  10,
  15_000_000n, // 50% full (at target)
  393216n      // 3 blobs (at target)
);
// stableFees[i] ≈ 1 gwei for all i

// Low utilization: fees fall
const fallingFees = FeeMarket.projectBaseFees(
  state,
  10,
  7_500_000n,  // 25% full (below target)
  131072n      // 1 blob (below target)
);
// fallingFees[9] < fallingFees[0]
Projection Analysis:
const projection = FeeMarket.projectBaseFees(state, 20, avgGasUsed);

// Find peak fee
const peakFee = projection.reduce((max, fee) => fee > max ? fee : max, 0n);
const peakIndex = projection.indexOf(peakFee);

console.log(`Peak: ${FeeMarket.weiToGwei(peakFee)} gwei at block ${peakIndex + 1}`);

// Calculate trend
const firstFee = projection[0];
const lastFee = projection[projection.length - 1];
const change = Number((lastFee - firstFee) * 100n / firstFee);

console.log(`Trend: ${change.toFixed(1)}% over ${projection.length} blocks`);
Setting Transaction Fees:
// Project worst case over 5 blocks
const projection = FeeMarket.projectBaseFees(
  state,
  5,
  28_000_000n // Assume high utilization
);

// Set maxFee to cover worst case + buffer
const maxProjectedFee = projection[projection.length - 1];
const maxFeePerGas = maxProjectedFee + 500_000_000n; // +0.5 gwei buffer

console.log(`Set maxFee to ${FeeMarket.weiToGwei(maxFeePerGas)} gwei`);

State Convenience Methods

State namespace provides this:-bound convenience methods:
const state: FeeMarket.State = { /* ... */ };

// Calculate next state
const next = FeeMarket.State.next.call(state);

// Get current blob base fee
const blobFee = FeeMarket.State.getBlobBaseFee.call(state);

// Get gas target
const gasTarget = FeeMarket.State.getGasTarget.call(state);

// Check utilization
const aboveGas = FeeMarket.State.isAboveGasTarget.call(state);
const aboveBlob = FeeMarket.State.isAboveBlobGasTarget.call(state);
See types.mdx and FeeMarket.js for details.

Implementation

Locations:
  • BrandedFeeMarket/calculateTxFee.js
  • BrandedFeeMarket/calculateBlobTxFee.js
  • BrandedFeeMarket/canIncludeTx.js
  • BrandedFeeMarket/nextState.js
  • BrandedFeeMarket/projectBaseFees.js
See branded-feemarket.mdx for implementation details.

References