BchainPay logoBchainPay
EngineeringEthereumLayer 2SettlementEIP-4844

EIP-4844 blobs and L2 settlement economics for crypto merchants

How EIP-4844 blob transactions cut L2 data costs 90% after Dencun, what that means for merchant treasury sweeps, and how to monitor the blob fee market.

By Cipher · Founding engineer, BchainPay8 min read
Illustration for EIP-4844 blobs and L2 settlement economics for crypto merchants

Before March 2024, accepting USDC on Base or Arbitrum came with a hidden floor cost. Your user saw a fee of a few cents, but underneath it, the rollup sequencer was posting transaction batches to Ethereum mainnet as calldata — 16 gas per non-zero byte, priced at whatever the mainnet gas market demanded. When mainnet was congested, that floor rose with it.

The Dencun upgrade (March 13, 2024) activated EIP-4844 and rebalanced that equation. Rollups now post batch data as blobs — a new transaction type with a separate fee market that starts near 1 wei per blob gas unit. Overnight, the median L2 data fee dropped 90-99%, and the economics of merchant settlement changed with it.

For payments infrastructure, three things changed: the minimum balance worth sweeping dropped by two orders of magnitude, the fee oracle you should use for cost estimates is no longer "EVM gas price × calldata size", and you now have a second fee market to monitor for circuit breakers.

What blobs actually are#

EIP-4844 introduced a new Ethereum transaction type: 0x03, the blob-carrying transaction. Each blob is a fixed-size 128 KB field attached to the transaction outside the EVM execution context. The key property: blob data is never accessible to the EVM. Solidity contracts cannot read it. It exists in the consensus layer only, and full nodes prune it after approximately 18 days (4096 epochs).

L2 rollups only need blob data available long enough for fraud provers (in optimistic rollups) or ZK verifiers to challenge a batch. They do not need it in EVM storage permanently. Blobs are exactly the right primitive for this job.

Each block can carry up to 6 blobs (current target: 3). The Ethereum consensus layer enforces the target via a blob gas mechanism analogous to EIP-1559:

blob_base_fee = MIN_BLOB_BASE_FEE × e^(excess_blob_gas / BLOB_BASE_FEE_UPDATE_FRACTION)

MIN_BLOB_BASE_FEE is 1 wei. BLOB_BASE_FEE_UPDATE_FRACTION is 3,338,477. When block-average blob count stays at the 3-blob target, excess blob gas accumulates slowly and the blob base fee stays near the minimum. It only spikes when demand pushes blocks to 5 or 6 blobs consistently.

Concrete cost comparison#

Here is what 128 KB of batch data costs before and after Dencun, at a 20 gwei EVM gas price (pre-Dencun baseline) and a 1,000 wei blob base fee (post-Dencun, elevated but realistic):

Route Unit cost Total for 128 KB USD (~$3,600/ETH)
Calldata (pre-Dencun) ~13 gas/byte avg ~1.66M gas × 20 gwei ~$120
Blob (post-Dencun) 1 blob_gas/byte 131,072 blob_gas × 1K wei ~$0.47

That is a 250× reduction at these reference prices. The long-run median blob base fee since Dencun has kept data costs in the $0.01-$0.50 per batch range, versus $50-$200 pre-Dencun.

What end-users observed: Arbitrum median fees dropped from roughly $0.08-$0.25 to $0.002-$0.01 within days of the upgrade. Base and OP Mainnet saw similar reductions.

Reading the blob fee market#

Blob gas metrics are part of the Ethereum block header since Dencun. Read them via standard JSON-RPC:

import { createPublicClient, http } from 'viem';
import { mainnet } from 'viem/chains';
 
const client = createPublicClient({ chain: mainnet, transport: http(RPC_URL) });
 
const block = await client.getBlock({ blockTag: 'latest' });
// block.blobGasUsed    – blob gas consumed this block
// block.excessBlobGas  – running excess above the 3-blob target
 
// Derive blob base fee from excessBlobGas (EIP-4844 §3.3 fakeExponential)
function blobBaseFee(excess: bigint): bigint {
  const MIN  = 1n;
  const FRAC = 3_338_477n;
  let result = 0n;
  let num = MIN * 1_000_000n;
  let den = 1n;
  for (let i = 1n; num > 0n; i++) {
    result += num / den;
    num = (num * excess) / (FRAC * i);
  }
  return result / 1_000_000n;
}
 
const fee = blobBaseFee(block.excessBlobGas ?? 0n);
console.log(`Blob base fee: ${fee} wei`);

Via cast, if you prefer a quick CLI check:

cast block latest --rpc-url $ETH_RPC --json \
  | jq '{blobGasUsed: .blobGasUsed, excessBlobGas: .excessBlobGas}'

On L2s, the BLOBBASEFEE opcode (0x4A, added in EIP-7516 as part of the Dencun bundle) lets smart contracts read the current blob base fee. The OP Stack's GasPriceOracle uses it post-Ecotone to price the L1 data component on-chain, which is what you want for accurate sweep cost estimation.

OP Stack fee oracle post-Ecotone#

On Base and OP Mainnet, the GasPriceOracle precompile at 0x420000000000000000000000000000000000000F exposes a getL1Fee(bytes) function returning the estimated L1 data fee for a given transaction. Before Ecotone, it priced via calldata byte counts. Post-Ecotone (activated the same day as Dencun on both chains), it uses the blob pricing model internally:

import { createPublicClient, http } from 'viem';
import { base } from 'viem/chains';
 
const GAS_PRICE_ORACLE = '0x420000000000000000000000000000000000000F' as const;
 
const ABI = [{
  name: 'getL1Fee',
  type: 'function',
  inputs:  [{ name: 'data', type: 'bytes' }],
  outputs: [{ name: '',     type: 'uint256' }],
}] as const;
 
const client = createPublicClient({ chain: base, transport: http(BASE_RPC) });
 
// Pass the raw calldata of the transaction you plan to submit on Base
const usdcTransferCalldata = '0xa9059cbb' +
  recipientAddress.slice(2).padStart(64, '0') +
  amount.toString(16).padStart(64, '0');
 
const l1Fee = await client.readContract({
  address: GAS_PRICE_ORACLE,
  abi: ABI,
  functionName: 'getL1Fee',
  args: [`0x${usdcTransferCalldata}`],
});
 
// Post-Dencun typical output: 100–500 wei (~$0.00035–$0.0018)
// Pre-Dencun typical output: 50,000–300,000 wei (~$0.18–$1.10)
console.log(`L1 data fee estimate: ${l1Fee} wei`);

Use this oracle — not manual calldata-size math — because it accounts for the OP Stack's internal compression ratio and the current blob base fee sourced from the BLOBBASEFEE opcode. Manual estimates will be off by 2-5× depending on transaction structure.

Sweep economics after Dencun#

Before Dencun, BchainPay kept a simple sweep rule: only clear a deposit address when the expected L1 data fee of the sweep transaction was below 1% of the USDC balance. At $0.08-$0.20 data fees on Base, that put the practical minimum at $8-$20 per address.

Post-Dencun, the same 1% rule at $0.001-$0.003 data fees lowers the floor to $0.10-$0.30. We run at a $0.50 minimum to absorb blob fee spikes, but that is still a 16-40× improvement over the pre-Dencun threshold. Addresses that previously sat unswept for days because their balance was under the sweep floor now clear within the hour.

Query the live sweep cost estimate before triggering an off-schedule sweep:

GET /v1/chains/base/sweep-estimate
Authorization: Bearer sk_live_…
{
  "chain": "base",
  "estimated_sweep_cost_usd": "0.0019",
  "evm_gas_used": 52000,
  "evm_gas_price_gwei": "0.005",
  "l1_data_fee_usd": "0.0009",
  "blob_base_fee_wei": "430",
  "timestamp": "2026-04-27T11:00:00Z"
}

Automatic sweeps are triggered when estimated_sweep_cost_usd is below your configured sweep_margin_pct of the pending balance. The API updates this value every 30 seconds from the live OP Stack fee oracle.

Circuit breaker for blob fee spikes#

Blob fees have hit 100,000+ wei during brief windows when multiple L2s push blobs simultaneously into a short block run. A sweep worker without a circuit breaker will lock in the inflated L1 data fee during the spike.

const BLOB_FEE_PAUSE_WEI = 15_000n; // alert threshold: ~15K wei blob base fee
 
async function sweepWorker(chain: 'base' | 'arbitrum' | 'optimism') {
  const { blob_base_fee_wei } = await fetch(
    `/v1/chains/${chain}/sweep-estimate`,
    { headers: { Authorization: `Bearer ${SK}` } }
  ).then(r => r.json());
 
  const blobFee = BigInt(blob_base_fee_wei);
 
  if (blobFee > BLOB_FEE_PAUSE_WEI) {
    logger.warn({ blobFee: blobFee.toString(), chain },
      'Blob base fee elevated — deferring non-urgent sweeps');
    return scheduleRetry(chain, 90_000); // retry in 90 seconds
  }
 
  const pending = await getPendingSweepAddresses(chain);
  for (const addr of pending) {
    const balance  = await getUsdcBalanceUsd(addr, chain);
    const sweepCost = parseFloat(blob_base_fee_wei) / 1e18 * ETH_PRICE_USD + EVM_GAS_COST_USD;
    if (balance > sweepCost * 100) {
      await enqueueSweep(addr, chain);
    }
  }
}

Historical data shows blob fee spikes above 15,000 wei resolve within 2-5 minutes in the vast majority of cases. A 90-second retry loop handles this without holding sweeps indefinitely.

Creating payment intents for L2 settlement#

Nothing changes in the intent creation API — BchainPay handles chain selection and blob-aware sweep routing internally:

POST /v1/payment-intents
Authorization: Bearer sk_live_…
Idempotency-Key: 01HWAB4DEFG5HIJ6KLM7NOP8QR
Content-Type: application/json
 
{
  "amount":     { "value": 15.00, "currency": "USD" },
  "accept":     ["USDC.base", "USDC.arbitrum", "USDC.optimism"],
  "metadata":   { "order_id": "ord_10512" },
  "expires_in": 900
}

When multiple L2 networks are in the accept list, BchainPay assigns the deposit chain dynamically based on current sweep cost. Since Dencun, Base has consistently offered the lowest per-transaction data fees of the three major OP Stack and Arbitrum networks.

The confirmed webhook includes a settlement_chain field:

{
  "event": "payment_intent.confirmed",
  "data": {
    "id": "pi_01HWAB4D…",
    "status": "confirmed",
    "settlement_chain": "base",
    "amount_received": { "value": "15.00", "currency": "USD" },
    "tx_hash": "0xabcd…ef12",
    "confirmed_at": "2026-04-27T11:05:23Z"
  }
}

Key takeaways#

  • Blob gas and EVM gas are separate fee markets. A high EVM gas price does not imply a high blob base fee, and vice versa. Monitor excessBlobGas and blobGasUsed independently from EVM base fee.
  • L2 data costs dropped 90-99% post-Dencun. If your sweep thresholds were calibrated before the upgrade, revisit them — you are likely deferring sweeps that are now economical to execute.
  • Use the OP Stack GasPriceOracle.getL1Fee for cost estimates, not manual calldata-size math. Post-Ecotone it prices via the blob model and accounts for internal compression ratios you cannot easily replicate manually.
  • Blob fee spikes are real but short. Build a circuit breaker that defers non-urgent sweeps above your margin threshold. A 90-second retry handles the vast majority of historical spikes.
  • Blob data is pruned after ~18 days. This does not affect payment finality — the L2 state root committed to Ethereum is permanent. Store your settlement receipts in Postgres, not by reference to blob availability.
  • ZK rollups also benefit from blobs, but proof verification gas dominates their cost profile rather than data gas. For general-purpose USDC settlement, OP Stack chains have the most predictable blob pricing and deepest stablecoin liquidity post-Dencun.

Try it yourself

Spin up a sandbox merchant in under 60 seconds.

One REST endpoint, signed webhooks, five chains. No credit card required.

Related reading