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.