gas-oracle. tutorial

Contents

  1. Why predict gas
  2. How blob fees work
  3. Live dashboard walkthrough
  4. Use the library
  5. How the predictor works
  6. Custom RPC endpoints
  7. Adding a new chain
  8. Next steps

1. Why predict gas

After EIP-4844 (Dencun, March 2024), the dominant cost of posting transactions on L2 rollups shifted from L1 calldata to blob fees -- a volatile, auction-based market that reprices every L1 block. Wallets and protocols that simply read the current blob base fee consistently over- or underpay:

gas-oracle solves this by predicting where blob fees are heading, not where they are now. Protocols can set tighter fee caps, sequencers can time batch submissions, and wallets can show users a realistic cost estimate instead of a stale one.

2. How blob fees work

EIP-4844 introduced a separate fee market for blobs. The blob base fee is computed deterministically from a single on-chain counter, excess_blob_gas, using the fake_exponential formula:

blob_base_fee = fake_exponential(MIN_BASE_FEE, excess_blob_gas, BLOB_BASE_FEE_UPDATE_FRACTION)

fake_exponential approximates factor * e^(numerator / denominator) via a Taylor series. Here is the JavaScript implementation from the dashboard:

js
function fakeExponential(factor, numerator, denominator) {
  let output = 0n;
  let term = factor * 1n;
  let i = 1n;
  while (term > 0n) {
    output += term;
    term = (term * numerator) / (denominator * i);
    i += 1n;
    if (i > 128n) break;   // safety bound
  }
  return output / denominator;
}

const MIN_BLOB_BASE_FEE        = 1n;           // 1 wei
const BLOB_BASE_FEE_UPDATE_FRACTION = 3338477n;

function blobBaseFeeFromExcess(excessBlobGas) {
  return fakeExponential(MIN_BLOB_BASE_FEE, excessBlobGas, BLOB_BASE_FEE_UPDATE_FRACTION);
}

The self-correcting mechanism is simple: each L1 block has a target of 3 blobs. If a block includes more than 3, excess_blob_gas increases and the fee rises exponentially. If it includes fewer, excess decreases and the fee drops. This creates a mean-reverting oscillation -- exactly the kind of signal a short-term predictor can exploit.

3. Live dashboard walkthrough

Open gas-oracle.kcolbchain.com. The page polls L1 and L2 RPCs every 12 seconds and displays two main sections:

L1 bar (top row)

Per-chain cards

One card each for Arbitrum, Optimism, Base, and Scroll. Each card shows:

4. Use the library

The dashboard is a lightweight preview. For production, use the full TypeScript library which adds regression-based confidence intervals.

typescript
import { GasOracle } from '@kcolbchain/gas-oracle'

const oracle = new GasOracle({
  l1Rpc: 'https://eth.llamarpc.com',
  chain: 'arbitrum',
  l2Rpc: 'https://arb1.arbitrum.io/rpc',
})

const prediction = await oracle.predict({ blocksAhead: 10 })

console.log(prediction)
// {
//   gasPrice:    0.012,      // gwei — predicted L2 execution gas price
//   blobFee:     0.0034,     // gwei — predicted L1 blob fee component
//   confidence:  0.87,       // 0-1 — how tight the prediction interval is
//   blocksAhead: 10,
//   chain:       'arbitrum',
// }

The Prediction type

typescript
interface Prediction {
  gasPrice:    number   // predicted L2 gas price in gwei
  blobFee:     number   // predicted blob base fee in gwei
  confidence:  number   // 0-1, higher = tighter interval
  blocksAhead: number   // how many blocks ahead
  chain:       string   // chain identifier
}
Tip: Call oracle.predict() right before submitting a transaction, then use prediction.gasPrice as your maxFeePerGas hint. The confidence field tells you how volatile the recent window is -- below 0.5, consider adding a safety buffer.

5. How the predictor works

Both the dashboard and the library use exponential moving average (EMA) smoothing as their core signal, but they differ in depth:

Dashboard (browser, simplified)

An EMA with α = 0.3 over a rolling window of up to 50 samples collected every 12 seconds. The smoothed value is the prediction. Fast, zero-dependency, good enough for a visual gauge.

js
function ema(series, alpha = 0.3) {
  let v = series[0];
  for (let i = 1; i < series.length; i++)
    v = alpha * series[i] + (1 - alpha) * v;
  return v;
}

Library (full, TypeScript)

EMA smoothing over a 50-block window plus ordinary least-squares linear regression on the residuals. The regression captures short-term directional momentum that the EMA alone lags behind. The confidence score is derived from the inverse of the regression's residual standard error -- tighter residuals mean a more predictable fee environment.

This two-layer approach keeps the median prediction error under 8% for 10-block forecasts in normal conditions, while the EMA-only dashboard version hovers around 12-15%.

6. Custom RPC endpoints

Public RPCs are rate-limited. For reliable data, supply your own endpoints.

Dashboard (query params)

url
# Override the L1 source (blob fee + base fee):
gas-oracle.kcolbchain.com?l1rpc=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY

# Override a specific chain:
gas-oracle.kcolbchain.com?rpc_arbitrum=https://arb-mainnet.g.alchemy.com/v2/YOUR_KEY

# Override all L2 chains with the same RPC (less common):
gas-oracle.kcolbchain.com?rpc=https://your-multi-chain-rpc.example.com

Library

typescript
const oracle = new GasOracle({
  l1Rpc: process.env.L1_RPC_URL,        // your Alchemy / Infura / self-hosted
  chain: 'base',
  l2Rpc: process.env.BASE_RPC_URL,
})
Rate limits: The dashboard polls every 12 seconds per chain. With 4 chains + L1, that is roughly 25 req/min. Most free-tier RPC plans handle this comfortably, but check your provider's limits before deploying in production.

7. Adding a new chain

Each supported L2 implements the ChainAdapter interface:

typescript
interface ChainAdapter {
  name: string                                          // e.g. 'zksync-era'
  computeL2Cost(blobBaseFee: bigint, l2ExecutionFee: bigint): bigint
}

computeL2Cost combines the L1 blob component with the L2-specific execution fee. Each chain calculates this differently -- Arbitrum uses an L1 data poster fee, Optimism uses an ecotone scalar, Base follows OP's formula, and Scroll adds a verification surcharge.

To add a new chain:

  1. Create a new adapter implementing ChainAdapter.
  2. Add the chain's default RPC and metadata to the CHAINS config.
  3. Register the adapter in the oracle factory.
  4. Submit a PR referencing issue #6, which tracks Scroll and zkSync Era adapter work.

8. Next steps