> ## Documentation Index
> Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Fee Market Calculations

<Card title="Try it Live" icon="play" href="https://playground.tevm.sh?example=primitives/fee-market.ts">
  Run FeeMarket examples in the interactive playground
</Card>

# Fee Market Calculations

Transaction fee calculations and state transitions.

## calculateTxFee

```typescript theme={null}
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:**

```typescript theme={null}
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:**

```typescript theme={null}
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

```typescript theme={null}
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:**

```typescript theme={null}
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:**

```typescript theme={null}
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

```typescript theme={null}
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:**

```typescript theme={null}
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:**

```typescript theme={null}
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

```typescript theme={null}
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](./eip1559.mdx#basefee)
* `excessBlobGas` - Calculated via [calculateExcessBlobGas](./eip4844.mdx#calculateexcessblobgas)
* `gasUsed` - Reset to 0
* `blobGasUsed` - Reset to 0
* `gasLimit` - Unchanged

**Examples:**

```typescript theme={null}
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:**

```typescript theme={null}
const nextState = FeeMarket.State.next.call(currentState);
// Same result
```

**Multi-block projection:**

```typescript theme={null}
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

```typescript theme={null}
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:**

```typescript theme={null}
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:**

```typescript theme={null}
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:**

```typescript theme={null}
// 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:

```typescript theme={null}
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](./types.mdx) and [FeeMarket.js](./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](./branded-feemarket.mdx) for implementation details.

## References

* [eip1559.mdx](./eip1559.mdx)
* [eip4844.mdx](./eip4844.mdx)
* [types.mdx](./types.mdx)
* [usage-patterns.mdx](./usage-patterns.mdx)
