Event decoding in indexer-core is driven by CombinedEventProcessor, which is configured for you through IndexerFactory.
The current event stack is:
AbiLoader: loads ABI JSON resources from the classpathAbiEventProcessor: decodes ABI events and optional VET transfersBusinessEventProcessor: derives higher-level business eventsCombinedEventProcessor: merges ABI events and business events into one output stream
In most applications you should configure event decoding through IndexerFactory rather than constructing processors manually.
val indexer =
IndexerFactory()
.name("events")
.thorClient(thorClient)
.processor(processor)
.abis("abis")
.abiEventNames(listOf("Transfer", "Approval"))
.abiContracts(listOf("0xabc..."))
.includeVetTransfers()
.build()That configuration builds a CombinedEventProcessor internally and emits decoded IndexedEvent values inside IndexingResult.
ABI files are loaded from the classpath, not from arbitrary filesystem paths.
AbiLoader scans a base resource directory for .json files up to two levels deep.
val events = AbiLoader.loadEvents(
basePath = "abis",
eventNames = listOf("Transfer", "Approval"),
)val functions = AbiLoader.loadFunctions(
basePath = "abis",
functionNames = listOf("balanceOf", "totalSupply"),
)Behavior to be aware of:
- if
eventNamesorfunctionNamesis empty, all matching ABI elements are loaded - duplicate ABI elements are deduplicated by signature shape
- if a requested name is not present, loading fails with
IllegalArgumentException - placeholder substitution is supported with
${NAME}syntax
Both ABI and business-event JSON can contain placeholders such as ${TOKEN_NAME}.
Values are resolved from:
- the substitution map you pass in
- environment variables
If any placeholders remain unresolved, loading fails.
AbiEventProcessor can decode events from either:
- a full
Block - Thor
EventLogandTransferLogpayloads
For each decoded ABI event it produces an IndexedEvent containing:
- block ID and block number
- timestamp
- transaction ID
- origin
- gas metadata when block data is available
- raw topics/data when present
- decoded parameter values in
params eventTypeclauseIndex
There are two layers of filtering.
Configured through the factory:
abiEventNames(...): load only selected ABI event namesabiContracts(...): accept events only from selected contract addresses
These filters are applied before decoding in LogsIndexer mode:
eventCriteriaSet(...)transferCriteriaSet(...)
This is the most efficient way to reduce remote log volume.
Native VET transfers are not ABI events, but the library can represent them as synthetic IndexedEvent values with:
eventType = "VET_TRANSFER"- params:
fromtoamount
Enable them with:
IndexerFactory()
.includeVetTransfers()This works in both block-based and log-based processing.
It is also enabled automatically when a configured business event definition depends on VET_TRANSFER.
EventUtils provides the low-level helpers used by the runtime:
getEventSignature("Transfer(address,address,uint256)")- ABI/topic matching
- indexed and non-indexed parameter decoding
ABI matching is based on:
- topic0 signature
- indexed parameter count
- optional contract-address filtering
If you need direct access to the event stack outside IndexerFactory, you can construct a combined processor manually:
val processor =
CombinedEventProcessor.create(
abiBasePath = "abis",
abiEventNames = listOf("Transfer"),
abiContracts = listOf("0xabc..."),
includeVetTransfers = true,
businessEventPath = null,
businessEventAbiBasePath = null,
businessEventNames = emptyList(),
businessEventContracts = emptyList(),
substitutionParams = emptyMap(),
)Then process either a block:
val events = processor.processEvents(block)or log payloads:
val events = processor.processEvents(eventLogs, transferLogs)When both ABI events and business events are enabled:
- business events are derived from decoded ABI events and optional VET transfers
- if a business event matches the same
txIdandclauseIndexas an ABI event, the ABI event is removed from the final output
This keeps the final event list focused on the higher-level semantic event where possible.
See BusinessEvents.md for the business-event definition model.