Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:26:05 +08:00
commit 8bcde7080b
26 changed files with 5957 additions and 0 deletions

View File

@@ -0,0 +1,151 @@
# Block Handlers
Run logic on every block or at intervals using the `onBlock` API (v2.29+).
## Basic Usage
```typescript
import { onBlock } from "generated";
onBlock(
{
name: "MyBlockHandler",
chain: 1,
},
async ({ block, context }) => {
context.log.info(`Processing block ${block.number}`);
}
);
```
**Note:** Block handlers don't require config changes or codegen runs.
## Options
| Option | Required | Description |
|--------|----------|-------------|
| `name` | Yes | Handler name for logging/metrics |
| `chain` | Yes | Chain ID to run on |
| `interval` | No | Block interval (default: 1 = every block) |
| `startBlock` | No | Block to start from |
| `endBlock` | No | Block to end at |
## Handler Function
**Important:** Block handlers require `preload_handlers: true` in config.yaml.
```typescript
onBlock(
{ name: "HourlyStats", chain: 1, interval: 300 },
async ({ block, context }) => {
// block.number - The block number
// block.chainId - The chain ID
// context - Same as event handlers
}
);
```
## Time-Based Intervals
Convert time to blocks:
```typescript
// Every 60 minutes on Ethereum (12s blocks)
const interval = (60 * 60) / 12; // 300 blocks
// Every 60 minutes on Optimism (2s blocks)
const interval = (60 * 60) / 2; // 1800 blocks
```
## Multichain Block Handlers
Use `forEach` for multiple chains:
```typescript
import { onBlock } from "generated";
[
{ chain: 1 as const, startBlock: 19783636, interval: 300 },
{ chain: 10 as const, startBlock: 119534316, interval: 1800 },
].forEach(({ chain, startBlock, interval }) => {
onBlock(
{ name: "HourlyPrice", chain, startBlock, interval },
async ({ block, context }) => {
// Handle block...
}
);
});
```
## Different Historical vs Realtime Intervals
Speed up historical sync with larger intervals:
```typescript
const realtimeBlock = 19783636;
// Historical: every 1000 blocks
onBlock(
{
name: "HistoricalHandler",
chain: 1,
endBlock: realtimeBlock - 1,
interval: 1000,
},
async ({ block, context }) => { /* ... */ }
);
// Realtime: every block
onBlock(
{
name: "RealtimeHandler",
chain: 1,
startBlock: realtimeBlock,
interval: 1,
},
async ({ block, context }) => { /* ... */ }
);
```
## Preset/Initial Data Handler
Load initial data on block 0:
```typescript
onBlock(
{
name: "Preset",
chain: 1,
startBlock: 0,
endBlock: 0,
},
async ({ block, context }) => {
// Skip preload phase for initial data
if (context.isPreload) return;
const users = await fetch("https://api.example.com/users");
for (const user of users) {
context.User.set({
id: user.id,
address: user.address,
name: user.name,
});
}
}
);
```
## Use Cases
- **Hourly/Daily aggregations** - Price snapshots, volume totals
- **Time-series data** - Create periodic data points
- **Initial state loading** - Populate entities on startup
- **State snapshots** - Capture state at intervals
## Limitations
- Requires `preload_handlers: true`
- Ordered multichain mode not supported
- Only EVM chains (no Fuel)
- No test framework support yet
- Only `block.number` and `block.chainId` available