Skip to main content

Event Handlers

Registration

A handler is a function that receives blockchain data, processes it, and inserts it into the database. You can register handlers in the file defined in the handler field in your config.yaml file. By default this is src/EventHandlers.* file.

import { <CONTRACT_NAME> } from "generated";

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

The generated module contains code and types based on config.yaml and schema.graphql files. Update it by running pnpm codegen command whenever you change these files.

Basic Example

Here's a handler example for the NewGreeting event. It belongs to the Greeter contract from our beginners Greeter Tutorial:

import { Greeter, User } from "generated";

// Handler for the NewGreeting event
Greeter.NewGreeting.handler(async ({ event, context }) => {
const userId = event.params.user; // The id for the User entity
const latestGreeting = event.params.greeting; // The greeting string that was added
const currentUserEntity = await context.User.get(userId); // Optional user entity that may already exist

// Update or create a new User entity
const userEntity: User = currentUserEntity
? {
id: userId,
latestGreeting,
numberOfGreetings: currentUserEntity.numberOfGreetings + 1,
greetings: [...currentUserEntity.greetings, latestGreeting],
}
: {
id: userId,
latestGreeting,
numberOfGreetings: 1,
greetings: [latestGreeting],
};

context.User.set(userEntity); // Set the User entity in the DB
});

Advanced Use Cases

HyperIndex provides many features to help you build more powerful and efficient indexers. Read more about these on separate pages:


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 fields (By default: number, timestamp, hash).
  • event.transaction – Transaction fields (eg hash, gasUsed, etc. Empty by default).
note

Configure block and transaction fields with field_selection in your config.yaml file.

Example event type definition:

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

Context Object

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

context.log

The context object also provides a logger that you can use to log messages to the console. Compared to console.log calls, these logs will be displayed on our Hosted Service runtime logs page.

Read more in the Logging Guide.


Accessing config.yaml Data in Handlers

You can access your indexer configuration within handlers using getConfigByChainId:

import { getConfigByChainId } from "../generated/src/ConfigYAML.gen";

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.