NestJS Event Listeners

NestJS Event Listeners

Although we covered a simple way to listen to events in the previous sections, the recommended way to listen to events is by using NestJS aware subscribers. This allows you to use the full power of the NestJS dependency injection framework. The following examples cover how to use nestjs managed event listeners where you're able to access and inject services into the subscriber. These achieve the same result as the event listening and block listening pages but with the added benefits of NestJS.

Event Subscribers

To create an event subscriber, extend the AbstractEventSubscriber class:

import { Injectable } from '@nestjs/common';
import {
  AbstractEventSubscriber,
  LogEvent,
  LogContext,
} from '@open-ethereum/indexer';
import { MyCustomService } from './my-custom.service';
 
@Injectable()
export class TransferSubscriber extends AbstractEventSubscriber {
  // Required: Specify the event pattern to listen for
  readonly eventPattern = 'ERC20:Transfer';
 
  constructor(
    private myCustomService: MyCustomService, // Inject your services
  ) {
    super();
  }
 
  // Optional: Handle indexing events
  async onIndex(payload: LogEvent, context: LogContext): Promise<void> {
    const { parsedEvent } = payload;
    const { from, to, value } = parsedEvent.args;
 
    await this.myCustomService.processTransfer(from, to, value);
  }
 
  // Optional: Handle de-indexing events (e.g., on chain reorganizations)
  async onDeindex(payload: LogEvent, context: LogContext): Promise<void> {
    // Handle event removal
  }
}

You can see here we've injected the MyCustomService service into the subscriber. This service is now available to use within the subscriber. This service must be registered in your app as a provider (opens in a new tab).

Block Subscribers

For block-level events, extend the AbstractBlockSubscriber class:

import { Injectable } from '@nestjs/common';
import {
  AbstractBlockSubscriber,
  BlockEvent,
  LogContext,
} from '@open-ethereum/indexer';
import { BlockAnalyticsService } from './block-analytics.service';
 
@Injectable()
export class BlockMetricsSubscriber extends AbstractBlockSubscriber {
  constructor(
    private blockAnalytics: BlockAnalyticsService, // Inject your services
  ) {
    super();
  }
 
  // Optional: Handle new blocks
  async onIndex(payload: BlockEvent, context: LogContext): Promise<void> {
    const { number, timestamp, transactions } = payload;
    await this.blockAnalytics.recordBlockMetrics(
      number,
      timestamp,
      transactions.length,
    );
  }
 
  // Optional: Handle block removals
  async onDeindex(payload: BlockEvent, context: LogContext): Promise<void> {
    // Handle block removal
  }
}

Registering Subscribers

Once you have your subscribers, you can register them in your NestJS module:

import { Module } from '@nestjs/common';
import { IndexerModule } from '@open-ethereum/indexer';
import { TransferSubscriber } from './transfer.subscriber';
import { BlockMetricsSubscriber } from './block-metrics.subscriber';
import { MyCustomService } from './my-custom.service';
import { BlockAnalyticsService } from './block-analytics.service';
 
@Module({
  imports: [IndexerModule.forRoot(indexerConfig)],
  providers: [
    TransferSubscriber,
    BlockMetricsSubscriber,
    MyCustomService,
    BlockAnalyticsService,
  ],
})
export class AppModule {}

Now they behave exactly the same as the event listeners and block listeners but have full access to the NestJS dependency injection framework.