Files
gh-enviodev-envio-plugins-p…/skills/hyperindex-development/references/wildcard-indexing.md
2025-11-29 18:26:05 +08:00

215 lines
5.0 KiB
Markdown

# Wildcard Indexing & Topic Filtering
Index events by signature without specifying contract addresses.
## Basic Wildcard Indexing
Index all events matching a signature across ALL contracts:
**config.yaml:**
```yaml
networks:
- id: 1
start_block: 0
contracts:
- name: ERC20
handler: ./src/EventHandlers.ts
events:
- event: Transfer(address indexed from, address indexed to, uint256 value)
# No address = wildcard indexing
```
**Handler:**
```typescript
import { ERC20 } from "generated";
ERC20.Transfer.handler(
async ({ event, context }) => {
context.Transfer.set({
id: `${event.chainId}_${event.block.number}_${event.logIndex}`,
from: event.params.from,
to: event.params.to,
token: event.srcAddress, // The actual contract address
});
},
{ wildcard: true } // Enable wildcard
);
```
## Topic Filtering
Filter wildcard events by indexed parameters:
### Single Filter
Only index mints (from = zero address):
```typescript
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
ERC20.Transfer.handler(
async ({ event, context }) => {
// Handle mint event...
},
{ wildcard: true, eventFilters: { from: ZERO_ADDRESS } }
);
```
### Multiple Filters
Index both mints AND burns:
```typescript
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
const WHITELISTED = [
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
];
ERC20.Transfer.handler(
async ({ event, context }) => {
// Handle mint or burn...
},
{
wildcard: true,
eventFilters: [
{ from: ZERO_ADDRESS, to: WHITELISTED }, // Mints to whitelisted
{ from: WHITELISTED, to: ZERO_ADDRESS }, // Burns from whitelisted
],
}
);
```
### Per-Network Filters
Different filters for different chains:
```typescript
const WHITELISTED = {
1: ["0xEthereumAddress1"],
137: ["0xPolygonAddress1", "0xPolygonAddress2"],
};
ERC20.Transfer.handler(
async ({ event, context }) => {
// Handle transfer...
},
{
wildcard: true,
eventFilters: ({ chainId }) => [
{ from: ZERO_ADDRESS, to: WHITELISTED[chainId] },
{ from: WHITELISTED[chainId], to: ZERO_ADDRESS },
],
}
);
```
## Wildcard with Dynamic Contracts
Track ERC20 transfers to/from dynamically registered contracts:
**config.yaml:**
```yaml
networks:
- id: 1
contracts:
- name: SafeRegistry
address: 0xRegistryAddress
handler: ./src/EventHandlers.ts
events:
- event: NewSafe(address safe)
- name: Safe
handler: ./src/EventHandlers.ts
events:
- event: Transfer(address indexed from, address indexed to, uint256 value)
# No address - dynamically registered
```
**Handler:**
```typescript
// Register Safe addresses dynamically
SafeRegistry.NewSafe.contractRegister(async ({ event, context }) => {
context.addSafe(event.params.safe);
});
// Track transfers to/from registered Safes
Safe.Transfer.handler(
async ({ event, context }) => {
context.Transfer.set({
id: `${event.chainId}_${event.block.number}_${event.logIndex}`,
from: event.params.from,
to: event.params.to,
});
},
{
wildcard: true,
eventFilters: ({ addresses }) => [
{ from: addresses }, // Transfers FROM Safe addresses
{ to: addresses }, // Transfers TO Safe addresses
],
}
);
```
## Filter in Handler
Additional filtering inside handler:
```typescript
const USDC = {
1: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
137: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
};
Safe.Transfer.handler(
async ({ event, context }) => {
// Only process USDC transfers
if (event.srcAddress !== USDC[event.chainId]) {
return;
}
context.USDCTransfer.set({
id: `${event.chainId}_${event.block.number}_${event.logIndex}`,
from: event.params.from,
to: event.params.to,
amount: event.params.value,
});
},
{
wildcard: true,
eventFilters: ({ addresses }) => [{ from: addresses }, { to: addresses }],
}
);
```
## Contract Register with Filters
Filter factory events when registering contracts:
```typescript
const DAI = "0x6B175474E89094C44Da98b954EedeAC495271d0F";
// Only register pools containing DAI
UniV3Factory.PoolCreated.contractRegister(
async ({ event, context }) => {
context.addUniV3Pool(event.params.pool);
},
{ eventFilters: [{ token0: DAI }, { token1: DAI }] }
);
```
## Use Cases
- **Index all ERC20 transfers** - Track any token transfer
- **Index all NFT mints** - Track mints across collections
- **Track protocol interactions** - Monitor transfers to/from your contracts
- **Cross-contract analysis** - Analyze patterns across all contracts
- **Factory-created contracts** - Index contracts created by factories
## Limitations
- Only one wildcard per event signature per network
- Either `contractRegister` OR `handler` can have eventFilters, not both
- RPC data source supports only single wildcard event with topic filtering