5.0 KiB
5.0 KiB
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:
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:
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):
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:
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:
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:
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:
// 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:
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:
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
contractRegisterORhandlercan have eventFilters, not both - RPC data source supports only single wildcard event with topic filtering