The price of a token on NEAR Intents is the ratio inside a trade that
`intents.near` actually executed; there is no pool, oracle or stored price,
and a 1Click quote is an offer. This reads `execute_intents` transactions on
the contract's shard, keeps the `token_diff` legs whose receipt succeeded and
whose intent is in `intents_executed`, and records one trade per asset/counter
pair per outcome, counting each unit once whichever side the taker was on.
- core: event parsing, trade building, shard lookup, price and VWAP, tested
against the logs of mainnet tx 85uy9uCF (USDT on Tron for ZEC).
- data: a NEAR client over the existing RpcClient, live then archival;
migration 0009 (intents_trade, intents_scan, near_token).
- api: a contiguous-cursor scan and a supply/listing poll per chain, and
GET /v1/chains/{chain}/intents/{swaps,price}. Prices are in counter-token
units; no USD until a stablecoin is named by contract.
Gated on `[chains.intents]`, which the config template leaves commented out:
FastNEAR's free RPC sustains about two requests a second against ~1.7 needed
to follow the tip, and neardata allows 30 blocks a minute. It waits for our
own node. A test renders the template and fails if the block is enabled.
Verified end to end against mainnet with ZEC configured: the trade at NEAR
218,261,895 was recorded and served by both routes.
Refs #27
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015pkwBsR54NRmZyU4QVhvfj
A header says who mined a block, not what they were paid: the amount is
remaining supply over an emission divisor plus fees, quantized with dust
carried forward, so only the `MinerRewarded` event knows it. Reading it means
decoding SCALE against the registry of the runtime that produced the block, and
this chain's shapes differ from vanilla Substrate because of the post-quantum
signatures.
So the chain describes itself. `state_getMetadata` at a block hash executes
`Metadata_metadata` against the runtime WASM in that block's state; the v14
registry that comes back drives a decoder that knows nothing about mining,
rewards or transfers. `INDEXED_EVENTS` is the only place a name appears —
adding transfers or anything the chain grows next is one line and a query, not
a migration, a struct and a decoder.
Metadata is cached per spec_version, because a node that starts pruning would
otherwise make history undecodable. Blocks are tried against the tip's runtime
first, which costs no extra call; `decode_events` refuses a partial read, so a
block from before an upgrade fails loudly rather than decoding into plausible
nonsense, and that failure is what asks which runtime actually produced it.
`backfill` walks outward from the tip — to the tip first, then toward genesis —
because live indexing alone leaves holes an account page would show: a restart,
an RPC blip, a gap fill that ran before the metadata was cached. Progress is a
cursor rather than `max(height)`, since a block with no indexed event and a
block never read are otherwise the same answer.
Verified on mainnet: block 13160's preimage derives, through the same Poseidon2
the chain runs, to exactly the `miner` field of its own reward event — so the
header author and the payee join with no lookup table.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jp6a8EDar9ueEhAxzep4V5
Cargo workspace plus a Vite frontend, following ~/git/architecture/generic.md.
Every block header carries its author's wormhole reward preimage in a `pow_`
PreRuntime digest, so authorship for the whole network is derivable from headers
alone — no indexer, no registration, no way for a miner to be left out. That
decoding, the hashrate maths and the telemetry name attribution live in
blackbeard-core with no I/O at all, so the parts that are easy to get subtly
wrong are exercised by unit tests rather than only against a live chain.
The browser holds one WebSocket: snapshot on subscribe, deltas thereafter. The
head stream is itself a push (chain_subscribeNewHeads), so a block reaches the
page the moment the node imports it. Messages are serialised once per broadcast,
and leaderboards are recomputed only for windows a socket is actually watching.
No RxJS — useSyncExternalStore is React's own contract for this.
Verified against the live Planck testnet: 12/12 headers decoded, telemetry names
attributed (quanpool-planck, baba-gorchitsa, …), warm start restoring 84 blocks
and 5 held names across a restart.
Three findings worth recording, all in CLAUDE.md:
- substrate-telemetry sends its JSON in *binary* frames. A text-only client
connects, subscribes, reports healthy and receives nothing at all — and a
Python probe hides it, because json.loads accepts bytes.
- Difficulty is a little-endian U512; decoding it big-endian gives a number
wrong by ~10^150 that still renders fine.
- Planck's real block interval is ~13-15s against a 6s target with enormous
variance, so a measured interval needs 20 tip samples before it is publishable.
Deploy assets, the Gitea Actions workflow and script/infra-setup.sh are included;
port 25864 is registered in architecture/port-allocations.md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MSDYiibCtELsrjQq6KXnoi