Skip to main content

Event Handlers

Event handlers define how your indexer processes blockchain events. After defining your configuration (config.yaml) and GraphQL schema (schema.graphql), generate the boilerplate code for event handlers by running:

pnpm codegen

Registering Event Handlers

Register an asynchronous handler for each blockchain event you want to process. The basic handler registration syntax is shown below:

import { <CONTRACT_NAME> } from "generated";

<CONTRACT_NAME>.<EVENT_NAME>.handler(async ({ event, context }) => {
// Your logic here
});

Event Object

Each handler receives an event object containing details about the emitted event, including parameters and blockchain metadata.

Accessing Event Parameters

Event parameters are accessed via:

event.params.<PARAMETER_NAME>

Example usage:

const sender = event.params.sender;
const amount = event.params.amount;

Additional Event Information

The event object also contains additional metadata:

  • event.chainId – Chain ID of the network emitting the event.
  • event.srcAddress – Contract address emitting the event.
  • event.logIndex – Index of the log within the block.
  • event.block – Block information (number, timestamp, etc.).
  • event.transaction – Transaction details (hash, index, gas used, etc.).

Example event type definition:

type Event<Params, TransactionFields, BlockFields> = {
params: Params;
chainId: number;
srcAddress: string;
logIndex: number;
transaction: TransactionFields;
block: BlockFields;
};

You can configure additional block and transaction fields in your config.yaml under field_selection.


Using the Handler context

The handler context provides methods to interact with entities stored in the database.

Retrieving Entities

Retrieve entities asynchronously using get:

await context.<ENTITY_NAME>.get(entityId);

Modifying Entities

Use set to create or update an entity:

context.<ENTITY_NAME>.set(entityObject);

Deleting Entities (Unsafe)

To delete an entity:

context.<ENTITY_NAME>.deleteUnsafe(entityId);
warning

The deleteUnsafe method is experimental and unsafe. Manually handle all entity references after deletion to maintain database consistency.


Updating Specific Entity Fields

Use the following approach to update specific fields in an existing entity:

const pool = await context.Pool.get(poolId);
if (pool) {
context.Pool.set({
...pool,
totalValueLockedETH: pool.totalValueLockedETH.plus(newDeposit),
});
}

Handler Example: NewGreeting Event

Here's a complete example handler for the NewGreeting event:

let { Greeter } = require("generated");

Greeter.NewGreeting.handler(async ({ event, context }) => {
let userId = event.params.user.toString();
let user = await context.User.get(userId);

if (user) {
context.User.set({
id: userId,
latestGreeting: event.params.greeting,
numberOfGreetings: user.numberOfGreetings + 1,
greetings: [...user.greetings, event.params.greeting],
});
} else {
context.User.set({
id: userId,
latestGreeting: event.params.greeting,
numberOfGreetings: 1,
greetings: [event.params.greeting],
});
}
});

Accessing config.yaml Data in Handlers

You can access your indexer configuration within handlers using getConfigByChainId:

const { getConfigByChainId } = require("../generated/src/ConfigYAML.bs.js");

Greeter.NewGreeting.handler(async ({ event, context }) => {
const config = getConfigByChainId(event.chainId);
});

This exposes configuration data such as:

  • syncSource, startBlock, confirmedBlockThreshold
  • Contract-specific data (abi, addresses, events)

Performance Considerations

For performance optimization and best practices, refer to:

These guides offer detailed recommendations on optimizing entity loading and indexing performance.