diff --git a/docs/base-chain/flashblocks/app-integration.mdx b/docs/base-chain/flashblocks/app-integration.mdx new file mode 100644 index 000000000..20ea39e1f --- /dev/null +++ b/docs/base-chain/flashblocks/app-integration.mdx @@ -0,0 +1,205 @@ +--- +title: App Integration +sidebarTitle: App Integration +description: Integrate Flashblocks into your app for 200ms transaction confirmations using RPC APIs and popular libraries like Ethers, Wagmi and Viem. +--- + +Choose the integration method that fits your use case: + +| Use Case | Recommended Approach | Documentation | +|----------|---------------------|---------------| +| **Apps needing instant UX** | Flashblocks-aware RPC with `pending` tag | [API Reference](/base-chain/api-reference/flashblocks-api/flashblocks-api-overview) | +| **Infrastructure providers** | Host Flashblocks-aware RPC nodes | [Enable Flashblocks](/base-chain/node-operators/run-a-base-node#enable-flashblocks) | +| **Standard apps** | Continue using regular RPCs | [JSON-RPC API Reference](/base-chain/api-reference/rpc-overview) | + + +Applications should avoid hard dependencies on the WebSocket stream. RPCs provide stable behavior and automatic failover to regular blocks if Flashblocks go down. + + +## RPC Endpoints + +For HTTP and WebSocket endpoint URLs, see the [Flashblocks API Reference](/base-chain/api-reference/flashblocks-api/flashblocks-api-overview). Public endpoints are rate-limited. For production use, connect through a Flashblocks-enabled node provider such as Alchemy, QuickNode, or dRPC. + +## Performance Characteristics + +| Metric | Value | +|--------|-------| +| Flashblock build time (P50) | ~10ms | +| Preconfirmation latency | ~200ms | +| Full block time | 2 seconds | +| Flashblocks per block | 10 | +| Reorg rate | < 0.1% | + +## Gas & Transaction Sizing + +The gas budget is **cumulative**, not per-Flashblock. Each Flashblock unlocks an additional 1/10 of the total block gas: + +| Flashblock | Cumulative Gas Available | +|------------|--------------------------| +| 1 | 1/10 of block limit (~18.75M gas) | +| 2 | 2/10 of block limit (~37.5M gas) | +| 3 | 3/10 of block limit (~56.25M gas) | +| ... | ... | +| 10 | Full block limit (~187.5M gas) | + + +**Unused gas carries forward.** If Flashblock 1 only uses 0.3/10 of gas, Flashblock 2 can use up to 1.7/10 (the cumulative 2/10 limit minus what's already been used). + + +**Implications for large transactions:** +- Transactions exceeding 1/10 of block gas (~18.75M) may not land in the first Flashblock — they wait until enough cumulative capacity exists. +- There is a separate **max gas limit per transaction** on Base, distinct from Flashblock capacity. +- If confirmation speed matters, keep individual transactions under ~18.75M gas to maximize the chance of inclusion in the earliest Flashblock. + +## Reliability & Fallback + +Base targets a **< 0.1% Flashblock reorg rate** — meaning a preconfirmation was streamed but not included in the final block. This is rare, but apps should account for it. + + +**Implement fallback logic.** Treat preconfirmations as strong signals, not guarantees. For critical operations, confirm against finalized block data. Check live reorg metrics at [base.org/stats](https://base.org/stats). + + +If Flashblocks become unavailable, the sequencer continues operating normally and confirmation falls back to standard 2-second blocks. Build your app to handle both cases gracefully. + +## Library Examples + +You will need to use a Flashblocks-aware RPC endpoint to use Flashblocks with the following libraries: + +### [Wagmi](https://wagmi.sh) + +To use Flashblocks with Wagmi, you will need to use the `basePreconf` chain in the Wagmi Config (see `config.ts`). + + + +```tsx Example.tsx +import { useSendTransaction, useWaitForTransactionReceipt } from "wagmi"; + +function SendTransaction() { + const { data: hash, sendTransaction } = useSendTransaction(); + const { data: receipt } = useWaitForTransactionReceipt({ hash }); + + return ( +
+ + {hash &&
Hash: {hash}
} + {receipt &&
Included on block number: {receipt.blockNumber}
} +
+ ) +} +``` + +```tsx App.tsx +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { WagmiProvider, useAccount } from 'wagmi' +import { config } from './config' +import { Example } from './Example' + +const queryClient = new QueryClient() + +function App() { + return ( + + + + + + ) +} +``` + +```tsx config.ts +import { createConfig, http } from "wagmi"; +import { baseSepoliaPreconf } from "wagmi/chains"; +import { baseAccount } from "wagmi/connectors"; + +export const config = createConfig({ + chains: [baseSepoliaPreconf], + connectors: [baseAccount()], + transports: { + [baseSepoliaPreconf.id]: http(), + }, +}); +``` + +
+ +### [Viem](https://viem.sh) + +```ts +import { createWalletClient, http, parseEther, publicActions } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import { baseSepoliaPreconf } from "viem/chains"; + +// Create client with the Flashblocks-aware chain. +const account = privateKeyToAccount(`0x${process.env.PRIVATE_KEY}`); +const client = createWalletClient({ + account, + chain: baseSepoliaPreconf, + transport: http(), +}) + .extend(publicActions); + +const submissionTime = new Date(); +console.log(`Submitting transaction at: ${submissionTime.toISOString()}`); + +// Send transaction. +const hash = await client.sendTransaction({ + to: "0x...", + value: parseEther('0.0001'), +}); +console.log(`Transaction hash: ${hash}`); + +// Wait for transaction to be included. +const receipt = await client.waitForTransactionReceipt({ hash }); +const confirmTime = new Date(); + +console.log(`Transaction included at: ${confirmTime.toISOString()}`); +console.log(`Time difference: ${confirmTime - submissionTime}ms`); +``` + +### [Ethers](https://github.com/ethers-io/ethers.js) + +```jsx +import { ethers } from "ethers"; + + const providerA = new ethers.JsonRpcProvider( + "https://sepolia.base.org" + ); + + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, providerA); + + try { + // Create a simple transaction (sending 0.001 ETH to a random address) + const tx = { + to: "", + value: ethers.parseEther("0.0000001"), + }; + + // Submit transaction + const submissionTime = new Date(); + const transaction = await wallet.sendTransaction(tx); + + console.log(`Submitting transaction at: ${submissionTime.toISOString()}`); + console.log(`Transaction hash: ${transaction.hash}`); + + await transaction.wait(0); // Make sure to set the confirmation count to 0 + + console.log("Transaction confirmed"); + const confirmationTime = new Date(); + console.log(`Transaction confirmed at: ${confirmationTime.toISOString()}`); + console.log(`Time difference: ${confirmationTime - submissionTime}ms`); + } +``` + +You should see the confirmation time significantly lower than the standard RPC endpoint. + +## 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).