Skip to content

EVM Adapters

processor.ts
// Import core types and classes from Subsquid's EVM processor package.
// These provide the building blocks for efficient EVM chain indexing.
import {
  BlockHeader,
  DataHandlerContext,
  EvmBatchProcessor,
  EvmBatchProcessorFields,
  Log as _Log,
  Transaction as _Transaction,
} from '@subsquid/evm-processor';
 
// Import ABI definitions for the contracts we want to listen to.
// These ABIs are used to decode event logs.
import * as printrAbi from './abi/printr';
import * as poolAbi from './abi/pool';
 
// Import shared types and config validation from Absinthe's common package.
import { TxnTrackingProtocol, validateEnv } from '@absinthe/common';
 
// Load and validate environment variables (including ABS_CONFIG).
// This ensures all required config is present and correctly typed.
const { txnTrackingProtocols } = validateEnv();
 
// Find the protocol config for the Printr bonding curve from the validated config.
// This tells us which contract, chain, and block range to index.
const printr = txnTrackingProtocols.find(p => p.type === TxnTrackingProtocol.PRINTR);
if (!printr) throw new Error('Printr protocol not found');
 
// Instantiate the EVM batch processor.
// This is the core engine that will scan blocks, filter logs, and extract data.
export const processor = new EvmBatchProcessor()
  // Set the Subsquid gateway URL for this chain (for fast block data).
  .setGateway(printr.gatewayUrl)
  // Set the fallback RPC endpoint (for on-demand data, e.g., traces).
  .setRpcEndpoint(printr.rpcUrl)
  // Define the block range to scan, based on config.
  .setBlockRange({
    from: printr.fromBlock,
    // Optionally set an upper bound if specified (0 or undefined means "no upper bound").
    ...(printr.toBlock ? { to: Number(printr.toBlock) } : {}),
  })
  // Wait for 75 block confirmations before processing (for chain finality).
  .setFinalityConfirmation(75)
  // Listen for key events from the Printr contract.
  //todo: When need to add new events, please modify over here
  .addLog({
    address: [printr.contractAddress],
    topic0: [
      printrAbi.events.CurveCreated.topic,
      printrAbi.events.TokenTrade.topic,
      printrAbi.events.LiquidityDeployed.topic,
    ],
    transaction: true, // Also fetch the full transaction for each log.
  })
  // Listen for Swap events from all the contracts (address is not filtered here).
  .addLog({
    topic0: [poolAbi.events.Swap.topic],
    transaction: true,
  })
  // Specify which fields to extract for logs and transactions.
  .setFields({
    log: { transactionHash: true },
    transaction: { to: true, from: true, gas: true, gasPrice: true, gasUsed: true },
  });
 
// Export strongly-typed aliases for downstream use.
// These types are parameterized by the processor's field selection.
export type Fields = EvmBatchProcessorFields<typeof processor>;
export type Block = BlockHeader<Fields>;
export type Log = _Log<Fields>;
export type Transaction = _Transaction<Fields>;
export type ProcessorContext<Store> = DataHandlerContext<Store, Fields>;

Notes

  • The adapter is config-driven via validateEnv(); nothing is hardcoded.
  • We select only required fields with .setFields(...) to keep processing fast and typed.
  • Add event handlers inside run() to decode events and push structured data to the Absinthe API.