DevelopersSeptember 14, 2026by
EmpoorioChain Core
EmpoorioChain Core

Indexing EmpoorioChain: Dynamic Metadata, Generated Types, and Ten Handlers That Could Never Fire

Two ways to index a Substrate chain

Dynamic metadata. Connect to a node, fetch its metadata at run time, decode blocks by name: "give me the Transfer event of pallet Balances". Flexible — survives runtime upgrades without recompiling — and unchecked: a name that does not exist simply never matches.

Generated types. Run subxt codegen against the metadata to produce Rust types for every pallet, call, event and storage item. Rigid — recompile per upgrade — and checked: a name that does not exist is a compile error.

What EmpooScan chose and what it cost

EmpooScan's indexer (~4,900 lines of Rust on subxt) uses dynamic metadata. The September 2026 audit found ten (pallet, event) pairs it listened for that do not exist in the runtime:

Indexer expectedRuntime has
MevProtection.CommitSubmitted / RevealedTxCommitted / TxRevealed
MevProtection.ValidatorSlashed
BlobStorage.BlobExpiredBlobPruned
AiServing.InferenceFulfilled / InferenceFailedInferenceCompleted / PruebaInvalida
Uniques.CollectionCreated / MintedCreated / Issued (the runtime uses Parity's pallet, not the local crate)
IdentitySsi.DidUpdated

None fired, ever. With generated types, all ten would have been compile errors.

Three more findings

  • 58 fields decoded with {:?}. The indexer formatted SCALE values with Rust's debug formatter in 46 places; what sits in the database is Value { value: Composite(…) } text, not addresses. The correct decoder existed a few functions away.
  • on_initialize / on_finalize events invisible. The listener lived inside the per-extrinsic loop; state-rent charges and blob pruning never reached the database.
  • No Balances.Transfer handler; EVM transactions attributed to System/Root.

The repair

  1. Use the existing address decoder everywhere a field is stored.
  2. Generate types from metadata per runtime version, so names are checked at compile time; keep a dynamic fallback only for pallets the indexer deliberately treats generically.
  3. Move event listening outside the extrinsic loop.
  4. Add Balances.Transfer and Ethereum.transact handlers.
  5. Put the database somewhere that does not go silent on a quota.

For anyone indexing EmpoorioChain

The metadata changes in every runtime upgrade (eight in ten days in September). Whichever approach you take, pin it to a spec version and re-check after each upgrade. The exchange-integration guide's advice — run your own indexer for deposits — stands until EmpooScan's repair lands.

The partnership this replaces

There is no data partner. There is one explorer, audited by its own ecosystem, with a written repair list.

Based on the EmpooScan audit (2026-09-02).

Share this article