Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 205 additions & 0 deletions docs/base-chain/flashblocks/app-integration.mdx
Original file line number Diff line number Diff line change
@@ -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) |

<Tip>
Applications should avoid hard dependencies on the WebSocket stream. RPCs provide stable behavior and automatic failover to regular blocks if Flashblocks go down.
</Tip>

## 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) |

<Tip>
**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).
</Tip>

**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.

<Warning>
**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).
</Warning>

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`).

<CodeGroup>

```tsx Example.tsx
import { useSendTransaction, useWaitForTransactionReceipt } from "wagmi";

function SendTransaction() {
const { data: hash, sendTransaction } = useSendTransaction();
const { data: receipt } = useWaitForTransactionReceipt({ hash });

return (
<div>
<button
onClick={() => sendTransaction({
to: "0x...",
value: parseEther('0.0001'),
})}
>
Send Transaction
</button>
{hash && <div>Hash: {hash}</div>}
{receipt && <div>Included on block number: {receipt.blockNumber}</div>}
</div>
)
}
```

```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 (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
</WagmiProvider>
)
}
```

```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(),
},
});
```

</CodeGroup>

### [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: "<SOME ADDRESS>",
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).