Flashblocks RPC
Flashblocks are sub-block preconfirmations produced every 200ms on Base. Read preconfirmed balances, nonces, receipts, and block data through standard JSON-RPC, or stream every flashblock as it lands.
Overview
Section titled “Overview”A single Base block (produced every 2 seconds) is divided into ten flashblocks streamed at 200ms intervals. Each flashblock is a delta containing new transactions and the resulting state changes. The Flashblocks RPC exposes this preconfirmed state through the standard Ethereum JSON-RPC interface by supporting the "pending" block tag.
Block N (2s)├── Flashblock 0 (0ms)├── Flashblock 1 (200ms)├── Flashblock 2 (400ms)├── Flashblock 3 (600ms)├── Flashblock 4 (800ms)├── Flashblock 5 (1000ms)├── Flashblock 6 (1200ms)├── Flashblock 7 (1400ms)├── Flashblock 8 (1600ms)└── Flashblock 9 (1800ms)Block N+1 (2s)└── ...Querying preconfirmed state
Section titled “Querying preconfirmed state”Pass "pending" to any supported JSON-RPC method to read the latest preconfirmed state. The same call against "latest" returns the last sealed block.
Check an account balance
Section titled “Check an account balance”eth_getBalance with the "pending" tag returns the balance reflecting every transaction included in the most recent flashblock — usually within 200ms of the user’s submission.
The hex result is the balance in wei.
curl -X POST https://your-base-rpc-endpoint \ -H "Content-Type: application/json" \ -d '{ "method": "eth_getBalance", "params": ["0xYourAddress", "pending"], "id": 1, "jsonrpc": "2.0" }'
# {# "id": 1,# "jsonrpc": "2.0",# "result": "0x1bc16d674ec80000"# }Get a transaction receipt
Section titled “Get a transaction receipt”After submitting a transaction, poll eth_getTransactionReceipt immediately — no need to wait for the next sealed block.
A preconfirmed receipt is identifiable by its zero blockHash. Once the parent block seals, the same receipt comes back with a real block hash.
curl -X POST https://your-base-rpc-endpoint \ -H "Content-Type: application/json" \ -d '{ "method": "eth_getTransactionReceipt", "params": ["0xYourTxHash"], "id": 1, "jsonrpc": "2.0" }'
# {# "result": {# "transactionHash": "0x...",# "blockHash": "0x000...000",# "blockNumber": "0x123",# "status": "0x1",# "gasUsed": "0x5208",# "logs": []# }# }Get the pending block
Section titled “Get the pending block”eth_getBlockByNumber with "pending" returns the in-progress block including every transaction landed in flashblocks so far.
Pass true as the second parameter for full transaction objects, false for hashes only.
curl -X POST https://your-base-rpc-endpoint \ -H "Content-Type: application/json" \ -d '{ "method": "eth_getBlockByNumber", "params": ["pending", true], "id": 1, "jsonrpc": "2.0" }'Get the pending nonce
Section titled “Get the pending nonce”eth_getTransactionCount against "pending" returns a nonce that already accounts for transactions sitting in flashblocks.
This avoids nonce collisions when an account submits many transactions in rapid succession.
curl -X POST https://your-base-rpc-endpoint \ -H "Content-Type: application/json" \ -d '{ "method": "eth_getTransactionCount", "params": ["0xYourAddress", "pending"], "id": 1, "jsonrpc": "2.0" }'
# {# "result": "0x5"# }Using ethers.js or viem
Section titled “Using ethers.js or viem”ethers.js
Section titled “ethers.js”Pass "pending" as the block tag to any read method to get preconfirmed values.
For receipts, poll getTransactionReceipt on a 200ms interval — that matches the flashblock cadence.
import { JsonRpcProvider } from "ethers";
const provider = new JsonRpcProvider("https://your-base-rpc-endpoint");
const balance = await provider.getBalance("0xYourAddress", "pending");const nonce = await provider.getTransactionCount("0xYourAddress", "pending");
async function waitForFlashblockReceipt(txHash, intervalMs = 200) { while (true) { const receipt = await provider.getTransactionReceipt(txHash); if (receipt) return receipt; await new Promise((r) => setTimeout(r, intervalMs)); }}viem accepts blockTag: "pending" on every read method. Receipts return as soon as the transaction is included in a flashblock.
import { createPublicClient, http } from "viem";import { base } from "viem/chains";
const client = createPublicClient({ chain: base, transport: http("https://your-base-rpc-endpoint"),});
const balance = await client.getBalance({ address: "0xYourAddress", blockTag: "pending",});
const nonce = await client.getTransactionCount({ address: "0xYourAddress", blockTag: "pending",});
const receipt = await client.getTransactionReceipt({ hash: "0xYourTxHash",});WebSocket streaming
Section titled “WebSocket streaming”For real-time updates, connect to the WebSocket endpoint and subscribe to flashblocks_v1. Each flashblock arrives as it is produced — five times per second.
Subscribing
Section titled “Subscribing”Open a WebSocket, send an eth_subscribe request with the flashblocks_v1 topic, and handle each eth_subscription message as it arrives.
flashblock.diff carries the new transactions and state changes since the previous flashblock; flashblock.index runs from 0 to 9 within each parent block.
import WebSocket from "ws";
const ws = new WebSocket("wss://your-base-ws-endpoint");
ws.on("open", () => { ws.send( JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_subscribe", params: ["flashblocks_v1"], }) );});
ws.on("message", (data) => { const msg = JSON.parse(data);
if (msg.method === "eth_subscription") { const flashblock = msg.params.result; console.log("Index:", flashblock.index); console.log("Txs:", flashblock.diff.transactions?.length ?? 0); }});Flashblock payload structure
Section titled “Flashblock payload structure”Each streamed flashblock contains:
| Field | Description |
|---|---|
payload_id | Identifier for the parent payload (block being built). |
index | Flashblock index within the current block (0, 1, 2, …). |
base | Present only on index 0. Contains the base execution payload. |
diff | Delta of transactions, receipts, and state changes since the previous flashblock. |
metadata | Additional metadata, including the flashblock access list if enabled. |
Error handling and fallback
Section titled “Error handling and fallback”Automatic fallback
Section titled “Automatic fallback”When the "pending" tag is used but no preconfirmed data is available — for example, during sequencer downtime or between blocks — the RPC falls back to the "latest" confirmed state. That means:
- Applications do not need special error handling for missing flashblock state.
- Results are always consistent: either preconfirmed or latest confirmed.
- The caller cannot distinguish a “pending equals latest” response from a fallback, so applications should not assume the data is fresher than the latest block.
Error responses
Section titled “Error responses”Standard JSON-RPC error codes apply:
| Scenario | Behavior |
|---|---|
| Invalid method parameters | Standard JSON-RPC error response with error code and message. |
| Transaction not found | null result (not an error). |
| Block not found | null result (not an error). |
| Flashblocks disabled | Falls back to standard RPC behavior. No error is returned. |
Detecting preconfirmed vs. finalized
Section titled “Detecting preconfirmed vs. finalized”A preconfirmed receipt can be identified by its blockHash:
- Preconfirmed —
blockHashis the zero hash. - Finalized —
blockHashis a real block hash.
function isPreconfirmed(receipt) { return ( receipt.blockHash === "0x0000000000000000000000000000000000000000000000000000000000000000" );}Further reading
Section titled “Further reading”- Flashblocks specification — full RPC method reference with parameter and return type details.
- Access lists specification — the FAL spec that accompanies flashblocks.
- Flashblocks pipeline — how flashblocks are produced and streamed internally.