From 83ce90f8f5f05a16e611aba44e6a4f2118aae372 Mon Sep 17 00:00:00 2001 From: Erhnysr Date: Mon, 6 Apr 2026 22:47:00 +0300 Subject: [PATCH 1/2] docs: add RPC usage clarification note Adds a clarification note about using the correct RPC endpoint when building on Base. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index d3d19bbbb..52dd475ce 100644 --- a/README.md +++ b/README.md @@ -164,3 +164,6 @@ The core team will review opened PRs. The SLA is 2 weeks, generally on a first-c ## Storybook for UI components See `storybook/README.md` for details on local Storybook and component docs. +## Additional Note + +When building on Base, always ensure that you are using the correct RPC endpoint for the intended network (mainnet or testnet). Misconfiguration can lead to failed transactions or unexpected behavior. From 32bbf32279443e8fa910939ea4fcd5d92974fdb0 Mon Sep 17 00:00:00 2001 From: erhan yasar Date: Mon, 13 Apr 2026 11:51:13 +0300 Subject: [PATCH 2/2] docs(flashblocks): add WebSocket streaming guide to app-integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The app-integration page covered RPC usage (viem, wagmi, ethers) but had no documentation for direct WebSocket streaming — a common pattern for real-time use cases like address monitoring and mempool tracking. Added a new WebSocket Streaming section covering: - Endpoint URLs for mainnet and sepolia - Flashblock message format (Brotli-compressed JSON, index 0 vs diff) - Basic connection example with Brotli decompression - Auto-reconnect with exponential backoff for production use - Address watcher pattern for real-time tx monitoring All examples are TypeScript and use only the built-in zlib module plus the ws package — no additional dependencies required. --- .../flashblocks/app-integration.mdx | 187 ++++++++++++++++++ 1 file changed, 187 insertions(+) diff --git a/docs/base-chain/flashblocks/app-integration.mdx b/docs/base-chain/flashblocks/app-integration.mdx index 9c3b3c890..83386ff39 100644 --- a/docs/base-chain/flashblocks/app-integration.mdx +++ b/docs/base-chain/flashblocks/app-integration.mdx @@ -198,6 +198,193 @@ console.log(`Time difference: ${confirmTime - submissionTime}ms`); You should see the confirmation time significantly lower than the standard RPC endpoint. + +## WebSocket Streaming + +For real-time monitoring — such as watching a specific address or tracking mempool activity — connect directly to the Flashblocks WebSocket stream. + + +Avoid hard dependencies on WebSocket in transaction-sending flows. Use WebSocket for monitoring only; use the RPC API for sending transactions and querying state. + + +### Endpoints + +| Network | WebSocket URL | +|---------|--------------| +| Mainnet | `wss://mainnet.flashblocks.base.org/ws` | +| Sepolia | `wss://sepolia.flashblocks.base.org/ws` | + +Public endpoints are rate-limited. For production use, connect through a Flashblocks-enabled node provider. + +### Message Format + +Flashblock messages are **Brotli-compressed JSON**. Each message represents one sub-block: + +- **`index: 0`** — contains full block header (`block_number`, `gas_limit`, `base_fee_per_gas`, `timestamp`) +- **`index: 1–9`** — contains only the diff: new transactions and receipts added in this sub-block + +```json +{ + "payload_id": "0x03997352d799c31a", + "index": 0, + "base": { + "block_number": "0x158a0e9", + "gas_limit": "0x3938700", + "base_fee_per_gas": "0xfa", + "timestamp": "0x67bf8332" + }, + "diff": { + "transactions": [...], + "receipts": [...] + } +} +``` + +### Basic Connection + +Install the `ws` package: + +```bash +npm install ws +``` + +```typescript +import WebSocket from "ws"; +import { brotliDecompressSync } from "zlib"; + +const WS_URL = "wss://mainnet.flashblocks.base.org/ws"; + +function parseFlashblock(data: Buffer) { + try { + // Messages are Brotli-compressed + return JSON.parse(brotliDecompressSync(data).toString()); + } catch { + // Some messages may arrive as plain JSON + return JSON.parse(data.toString()); + } +} + +const ws = new WebSocket(WS_URL); + +ws.on("open", () => console.log("Connected to Flashblocks")); + +ws.on("message", (data: Buffer) => { + const flashblock = parseFlashblock(data); + const txCount = flashblock.diff?.transactions?.length ?? 0; + console.log(`Flashblock #${flashblock.index}: ${txCount} transaction(s)`); +}); + +ws.on("error", (err) => console.error("WebSocket error:", err.message)); +ws.on("close", () => console.log("Disconnected")); +``` + +### Auto-Reconnect + +Production apps should reconnect automatically when the connection drops: + +```typescript +import WebSocket from "ws"; +import { brotliDecompressSync } from "zlib"; + +const WS_URL = "wss://mainnet.flashblocks.base.org/ws"; + +function createFlashblocksClient(onFlashblock: (data: unknown) => void) { + let ws: WebSocket | null = null; + let reconnectDelay = 1000; + + function connect() { + ws = new WebSocket(WS_URL); + + ws.on("open", () => { + console.log("Connected to Flashblocks"); + reconnectDelay = 1000; // reset on successful connection + }); + + ws.on("message", (data: Buffer) => { + try { + const decompressed = brotliDecompressSync(data); + onFlashblock(JSON.parse(decompressed.toString())); + } catch { + try { onFlashblock(JSON.parse(data.toString())); } catch { /* ignore */ } + } + }); + + ws.on("close", () => { + console.log(`Reconnecting in ${reconnectDelay}ms...`); + setTimeout(() => { + reconnectDelay = Math.min(reconnectDelay * 2, 30000); + connect(); + }, reconnectDelay); + }); + + ws.on("error", (err) => { + console.error("WebSocket error:", err.message); + ws?.close(); + }); + } + + connect(); + return { disconnect: () => ws?.close() }; +} + +// Usage +const client = createFlashblocksClient((flashblock) => { + console.log("New flashblock:", flashblock); +}); + +process.on("SIGINT", () => { client.disconnect(); process.exit(0); }); +``` + +### Watch a Specific Address + +Monitor an address for incoming or outgoing transactions in real-time: + +```typescript +import WebSocket from "ws"; +import { brotliDecompressSync } from "zlib"; + +interface FlashblockTx { + hash: string; + from: string; + to: string | null; + value: string; +} + +interface Flashblock { + index: number; + diff?: { transactions?: FlashblockTx[] }; +} + +function watchAddress(address: string) { + const target = address.toLowerCase(); + const ws = new WebSocket("wss://mainnet.flashblocks.base.org/ws"); + + ws.on("open", () => console.log(`Watching ${address}`)); + + ws.on("message", (data: Buffer) => { + let flashblock: Flashblock; + try { + flashblock = JSON.parse(brotliDecompressSync(data).toString()); + } catch { + try { flashblock = JSON.parse(data.toString()); } catch { return; } + } + + for (const tx of flashblock.diff?.transactions ?? []) { + if (tx.from?.toLowerCase() === target || tx.to?.toLowerCase() === target) { + const valueEth = Number(BigInt(tx.value)) / 1e18; + console.log(`\nTransaction detected in flashblock #${flashblock.index}`); + console.log(` Hash: ${tx.hash}`); + console.log(` From: ${tx.from}`); + console.log(` To: ${tx.to ?? "contract creation"}`); + console.log(` Value: ${valueEth.toFixed(6)} ETH`); + } + } + }); +} + +watchAddress("0xYourAddressHere"); +``` + ## Support For feedback, support or questions about Flashblocks, please don't hesitate to contact us in the `#developer-chat` channel in the [Base Discord](https://base.org/discord).