Subsquid Processor:
Imports
import {
BlockHeader,
DataHandlerContext,
EvmBatchProcessor,
EvmBatchProcessorFields,
Log as _Log,
Transaction as _Transaction,
} from '@subsquid/evm-processor';
import * as univ2Abi from './abi/univ2';
import { ProtocolType, validateEnv } from '@absinthe/common';
What's happening?
- Subsquid EVM Processor: Imports types and classes for block, log, transaction, and the batch processor itself.
- Uniswap V2 ABI: Imports the ABI definitions for Uniswap V2 events (Swap, Transfer).
- Absinthe Common: Imports protocol type enum and config/environment validation.
Environment & Config Validation
const env = validateEnv();
- Loads and validates your environment variables and config (including ABS_CONFIG).
- Ensures all required fields are present and correctly typed.
Select Uniswap V2 Protocol Config
const uniswapV2DexProtocol = env.dexProtocols.find(dexProtocol => {
return dexProtocol.type === ProtocolType.UNISWAP_V2;
});
if (!uniswapV2DexProtocol) {
throw new Error('Uniswap V2 protocol not found');
}
- Finds the Uniswap V2 protocol config from your validated config.
- Throws an error if not found (prevents silent misconfiguration).
Prepare Pool Addresses and Block Range
const contractAddresses = uniswapV2DexProtocol.protocols.map(protocol => protocol.contractAddress);
const earliestFromBlock = Math.min(...uniswapV2DexProtocol.protocols.map(protocol => protocol.fromBlock));
- contractAddresses: Array of all Uniswap V2 pool contract addresses to index.
- earliestFromBlock: Finds the lowest fromBlock among all pools—this is where indexing starts.
Configure the EVM Batch Processor
export const processor = new EvmBatchProcessor()
.setGateway(uniswapV2DexProtocol.gatewayUrl)
.setRpcEndpoint(uniswapV2DexProtocol.rpcUrl)
.setBlockRange({
from: earliestFromBlock,
...(uniswapV2DexProtocol.toBlock !== 0 ? { to: Number(uniswapV2DexProtocol.toBlock) } : {}),
})
.setFinalityConfirmation(75)
.addLog({
address: contractAddresses,
topic0: [univ2Abi.events.Transfer.topic, univ2Abi.events.Swap.topic],
transaction: true,
})
.setFields({
log: {
transactionHash: true,
},
transaction: {
to: true,
from: true,
gas: true,
gasPrice: true,
gasUsed: true,
},
});
What does each part do?
-
setGateway: Sets the Subsquid gateway URL for fast block data access (from config).
-
setRpcEndpoint: Sets the fallback RPC endpoint for on-demand data (from config).
-
setBlockRange:
from
: Start indexing from the earliest pool's fromBlock.to
: If toBlock is set in config, stop at that block; otherwise, keep syncing to latest.
-
setFinalityConfirmation(75): Waits for 75 block confirmations before processing (prevents reorg issues).
-
addLog:
address
: Listens for logs from all specified pool contract addresses.topic0
: Filters for only Transfer and Swap events (Uniswap V2 core events).transaction: true
: Also fetches the full transaction for each log (needed for gas, sender, etc).
-
setFields:
log
: Only extracts the transactionHash field from logs (for linking events to transactions).transaction
: Only extracts the fields you need (to, from, gas, gasPrice, gasUsed) for analytics and cost calculations.
Type Exports for Strong Typing
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>;
- Fields: Type representing the selected fields for logs and transactions.
- Block, Log, Transaction: Strongly-typed objects for each block, log, and transaction, parameterized by your field selection.
- ProcessorContext: Context object for event handlers, includes store access and selected fields.
How Does This All Work Together?
-
Config-driven: All pool addresses, chain info, and block ranges come from your config—no hardcoding.
-
Efficient event filtering: Only listens for relevant events (Swap, Transfer) from the pools you care about.
-
Lean data extraction: Only pulls the fields you need for analytics, keeping processing fast and memory usage low.
-
Strong typing: All downstream code (event handlers, analytics, API integration) can use these types for safety and autocompletion.
-
Ready for extension:
- Add more pools by editing your config, not your code.
- Add more event types by updating the topic0 array.