An explorer is where a chain becomes visible. EmpooScan is EmpoorioChain's, and it is a good example of the ecosystem's recurring pattern: real, substantial, and disconnected at one link. This post is its measured state.
What it is
- Site:
empooscan.com, live on Vercel, HTTP 200. About 35,700 lines of TypeScript: 75 pages and 70 API routes — blocks, extrinsics, events, accounts, validators, and pallet-specific views for MEV protection, blobs, AI serving, intents and domains. - Indexer: ~4,900 lines of Rust using subxt with dynamic metadata, writing to Postgres.
- Genesis: correctly
0xe973931e…eae7aa(the audit confirmed the site was on the live chain, not the retired one).
What the audit measured (2 September 2026)
The indexer was stopped since 1 September, its local database ~19,000 blocks behind. The production database was dead: the hosted Postgres had exhausted its free quota a month earlier, and /api/health reported db.connected: false. The site rendered; the data behind it did not update.
58 fields were stored as debug strings. In 46 places (plus 12 through a helper), the indexer "decoded" a SCALE value with Rust's {:?} formatter. What sits in the database under intents.creator, identity_dids.did, blobs.submitter is the literal text Value { value: Composite(Unnamed([...])), context: 11 }, not an address. The correct decoder already existed in the same codebase, six functions away.
Ten event handlers could never fire. They listened for (pallet, event) names that do not exist in the runtime — MevProtection.CommitSubmitted (real: TxCommitted), BlobStorage.BlobExpired (real: BlobPruned), AiServing.InferenceFulfilled (real: InferenceCompleted), Uniques.CollectionCreated (real: Created; the runtime uses Parity's pallet, not the local crate), IdentitySsi.DidUpdated (does not exist). Because the indexer uses dynamic metadata rather than generated code, a misspelt name fails neither at compile time nor at run time. With subxt codegen these would have been ten compile errors.
Events from on_initialize/on_finalize were invisible — the listener lived inside the per-extrinsic loop, so state-rent charges and blob pruning never reached the database. Balances.Transfer had no handler. EVM transactions were attributed to System/Root, because an Ethereum.transact has no Substrate signer.
Coverage: the explorer's own document claimed 21 of 21 pallets, 100 %. The runtime has 143 pallets in the default build; real coverage is about 14 %. The 100 % was against its own list.
Nodes: the site counted the public RPC hostname and "Node 1" as two nodes — same IP, same peer id — so uptime and region panels double-counted one machine.
Why publish this about your own explorer
Because a block explorer that shows stale or misdecoded data is worse than none: it lends the authority of a clean UI to wrong numbers. The audit's three fixes are ordered — use the existing address decoder everywhere, generate types from metadata so event names are checked at compile time, move the event listener outside the extrinsic loop — and the indexer is being moved to a database that will not go silent on a quota.
What EmpooScan will be
The mainnet gate names it: deployed at empooscan.com with TLS and genesis data, publishing runtime-upgrade hashes and metadata diffs, showing validators from chain state. The site is there. The indexer behind it is the work.
Based on the EmpooScan audit (2026-09-02, six agents; every figure measured) and RED.json.


