Contents
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:
- Overpay if they pad the fee during a spike that is already subsiding.
- Underpay (and get stuck) if they quote a calm-period fee right before a burst of blob demand.
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)
- L1 block -- latest Ethereum mainnet block number.
- L1 base fee -- the EIP-1559 execution base fee in gwei.
- Blob base fee -- computed from
excess_blob_gasviafake_exponential. Color-coded: green (< 5 gwei), amber (5-50 gwei), red (> 50 gwei). - Excess blob gas -- the raw counter that drives the blob fee.
Per-chain cards
One card each for Arbitrum, Optimism, Base, and Scroll. Each card shows:
- Live gas price -- the current L2 gas price in gwei (large number at top).
- Predicted (10 blk) -- the 10-block-ahead forecast using an EMA over the in-memory sample window.
- Sparkline -- a mini SVG chart of the last 50 price samples.
- Trend -- percentage change between the recent 3-sample average and the prior 3-sample average, with directional arrows.
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
}
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,
})
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:
- Create a new adapter implementing
ChainAdapter. - Add the chain's default RPC and metadata to the
CHAINSconfig. - Register the adapter in the oracle factory.
- Submit a PR referencing issue #6, which tracks Scroll and zkSync Era adapter work.
8. Next steps
- Live dashboard -- watch the predictor in action.
- GitHub repo -- source, issues, contributions.
- Issue #3 -- unit tests for the EMA + regression predictor.
- Issue #6 -- Scroll + zkSync Era chain adapters.
- EIP-4844 spec -- the full proto-danksharding proposal.
- Library docs -- API reference and configuration guide.