Verifiable on-chain history on Portaldot
on-chain
history,
no servers.
Load any dApp’s history in seconds, straight from Portaldot. Every chunk is checked against the source chain in your browser: no indexer, no API, no trust.
// open polkadot-ah.balance-history
// in the browser, no server
▸ registry
latest manifest from PotluckRegistry
on Portaldot V3 (pallet-revive)▸ fetch
chunk 0 via bitswap_v1_get
blocks #22,021,128 – #22,071,133▸ L1 integrity
rawHash 0xb826c80c… matches the manifest
canonical rows, bloom checked▸ L3 reconcile
every balance delta against System.Account
on Polkadot Asset Hub itselfSourcing history from
Polkadot Asset Hub
Kusama Asset Hub
Portaldot V3
See history verify itself
Pantry loads Polkadot Asset Hub from Portaldot in seconds, not the ~11 minutes a direct sync takes, and reconciles every account against the chain. Forge one row and it names the exact amount.
How it works
Four steps from a spec to a history every user can check for themselves.
- 01
Describe
A JSON spec names the events to index, the row each one becomes, and how rows reconcile with chain state.
specs/*.json - 02
Build
The publisher reads finalized blocks, decodes each with the runtime that executed it, and writes canonical NDJSON chunks.
potluck build · potluck verify - 03
Publish
Chunks go into Portaldot’s TransactionStorage and the manifest into the PotluckRegistry contract, in one batch.
potluck publish - 04
Load & verify
Any browser reads the registry, fetches chunks over bitswap, checks L1 · L2 · L3 against the source chain, then tails new blocks.
@potluck/client · Pantry
Everything an indexer does; nothing you have to trust.
- pantry · verify
// an honest accountL1 digest · rawHash · bloomokL2 rows re-derived from blocks183 / 183L3 Σ rows = Δ System.Accountexact · 1.8 s // a forged chunk, re-hashed by the forgerL1 digest · rawHash · bloompassesL2 rows re-derived from blockspassesL3 accounts reconcile903 / 904 ✗ off by exactly the hidden amountVerifiable history
Know it’s true
L1 checks every chunk’s hashes, L2 re-derives an account’s rows from their blocks, and L3 reconciles every balance against the chain itself. A forged chunk is caught to the exact amount.
- publish · portaldot-v3
// publisher, oncetransactionStorage.store(chunk 0)2.5 MBtransactionStorage.store(chunk 1)0.65 MButility.batchAll([ transactionStorage.store(manifest), revive.call(PotluckRegistry.publish)manifest #3]) // every browser, afterregistry 0xef93…82eb → manifest #3eth_callbitswap_v1_get(chunk 0 CID)2.5 MB · ≈ 4 sPortaldot data layer
Know where it lives
Chunks live in Portaldot’s TransactionStorage, manifests in a PotluckRegistry contract on pallet-revive, and browsers fetch them with bitswap_v1_get. No server, no bucket, no API key.
- client · coverage plan
portaldot-v3 · unified-historysnapshot #1 – #129,069manifest #2direct #129,070 – headlive tailmixed sync, L3 938 / 9383.0 s polkadot-asset-hub · balance-historysnapshot #22,021,128 – #22,101,127manifest #3direct #22,101,128 – headlive tail80,000 blocks from the snapshotnot ≈ 11 minAdaptive sync
Know what’s fastest
Direct sync when a chain is cheap (Portaldot V3: genesis to head in a browser), snapshots when it’s heavy, and a live tail of new finalized blocks either way.
- specs/polkadot-ah.balance-history.json
{ "source": { "chain": "polkadot-asset-hub", "fromBlock": 11405259 }, "columns": ["kind", "from", "to", "amount"], "match": [ { "pallet": "Balances", "event": "Transfer" },row { "pallet": "System", "event": "KilledAccount",reset "effect": "reset" }, … ], "reconcile": { "storage": "System.Account" }}Declarative specs
Know what’s indexed
One JSON file says which events become which rows and how they reconcile. No handler code: the same spec over the same blocks gives the same rawHash on any machine.
Give any dApp its history,
verified and serverless.
Write one spec and every user gets a history they can load in seconds and check themselves. No indexer to run, no API to rent.
Wallet & account history
Every DOT balance change of an account, reconciled to the planck against Asset Hub.
Try itInheritance & recovery
Recovery timelines from Kusama Asset Hub, rebuilt from storage and replayed 133 / 133.
Try itToken & NFT transfers
ERC-20 and ERC-721 Transfer logs from pallet-revive contracts, in the same pipeline as native POT.
Try itStatic dashboards
Ship a dashboard as static files: the data comes from Portaldot, not from your server.
Try itAudits & reconciliation
Every row sums to the on-chain balance; a forged row shows up as the exact amount it hides.
Try itYour dApp’s history
Describe your events in a JSON spec, build, publish to Portaldot. Same spec, same rawHash.
Try it
History that ships as a spec and a few blobs, not as an indexer you run forever.
Proof, not promises
On-chain. Check it yourself.
Every address and block below is on the Portaldot V3 testnet.
PotluckRegistry (EVM)
0xef93…82eb on Portaldot V3, deployed at block #129,014.
Deploy transaction
0x3abb…0352, storage deposit 433.2 tPOT. Open in explorer.
Manifest #2
Portaldot V3 history, blocks #1–#129,069, registered at block #129,095.
Manifest #3
Polkadot AH, 80,000 blocks and 114,460 rows for 372.64 tPOT, registered at block #129,233.
Tested contracts
21 Foundry tests, 100% coverage; EVM and PVM bytecode pass ReviveApi dry runs. Source.
Public on GitHub
Spec, core, client, CLI and both apps in one repo. wngstnr-code/potluck.