GET /v1/chains/{chain}/wormhole/deposits?to=<addr>,…&after=<h>:<i>&limit=<n>
Every Wormhole::NativeTransferred to up to 100 addresses (SS58 or 0x hex),
oldest first, with a height:event_index cursor. A deposit carries its
recipient, its amount as a decimal string, its transfer_count and its
leaf_index: what a wallet needs to work out what it can still spend.
A wormhole address's System::Account balance is a receipt total. An exit
credits the exit account and records a nullifier, and never debits the
wormhole address. A deposit is spent when the nullifier its secret and
transfer_count derive is used. The wallet computes and checks that itself;
nothing here asks for nullifiers, because naming one pairs a deposit with its
exit.
This is for the Quantus extension's wormhole balance (quantus/extension#14),
which would otherwise ask Quantus's Subsquid and tell Quantus which addresses
are one person's.
- The query reads chain_event through the accounts GIN index, then keeps only
rows whose `to` is one of the addresses: accounts holds the sender too, and
a transfer from a wormhole address is not a deposit to it.
- The response carries indexed_from/indexed_to. On a chain still backfilling,
a client can't take the sum as a balance without checking it against
Wormhole::TransferCount.
- CORS on this route alone allows any origin, GET only, merged outside the
site's allowlist so that allowlist can never answer a preflight for it.
Extension origins can't be listed (Chrome ids vary by install, Firefox's are
random per install), and the data is public.
The integration test covers the ways this is silently wrong: a deposit from an
address counted as one to it, another event kind leaking in, a cursor that
skips a same-block sibling, and another chain's rows. Unit tests cover both
address spellings, the cursor, and u128 amounts written as strings.
Closes#22
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f