A network page: the figures an analyst needs to judge ecosystem health #17
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The site answers "who is mining" thoroughly and "what is this economy doing" not at all. Everything needed is already reachable; none of it is assembled anywhere.
What is available, measured rather than assumed
Chain state, one read each, already surfaced individually on
/state:Map sizes, counted by enumeration on mainnet:
state_queryStorageAtexists and returns many values in one call — 1,914 account balances is two round trips, not 1,914. That is what makes distribution metrics affordable at all.Our own index is complete for mainnet: blocks
1 .. 42,203, from genesis. Per-day activity is therefore honest here. It is not complete on the testnets, which are still walking backwards, so any per-day figure has to carry the range it was computed over.What to show
Supply. Total issuance; endowed at genesis (5,670,000, which
/genesisalready computes); mined since genesis, which is the difference and is the real emission-to-date; fees collected.On "circulation", carefully. Nothing is locked through the balances pallet — Locks, Holds, Freezes and Reserves are all empty, counted rather than assumed. So the naive circulating figure equals total issuance, and printing "circulating supply" as a headline would be asserting a distinction this chain does not currently make. Better to state what was counted: nothing is locked, with the counts beside it, and let that be read. The 48 vesting schedules are worth showing as their own count — they do not touch
Balances::Locks, so whatever this runtime's customVestingdoes, it is not a balance lock, and claiming otherwise without reading the pallet would be a guess.Distribution, which is the part that actually answers "ecosystem health": accounts on chain, how many hold a non-zero balance, and the share of issuance held by the top 1, 10 and 100. A Gini coefficient is cheap once every balance is in hand and is the single most legible summary of concentration. This needs a cached background computation like
cached_roles, not a per-request read.Activity per day, from our index: extrinsics split signed against inherent — most traffic on this chain is inherents and a single "transactions per day" line would be mostly timestamps — distinct signers, new accounts first seen, blocks, and distinct miners.
Capability, as a headline rather than a table: calls used of declared, events fired of declared, vesting schedules, referenda, reversible transfers.
/callshas the detail; the summary belongs here because "shipped and never used" is an ecosystem statement.Order
Cheap things first: supply, capability, and the per-day series. Distribution second, because it needs a cache and a background task, and because getting the top-N share wrong is worse than not showing it.
Every per-day figure must carry the indexed range it was computed over. On mainnet that is all of it; on a testnet still backfilling it is not, and a chart that quietly covers a different period than its axis claims is the failure mode this repository has hit twice already.
Correction: the page's reason for omitting circulating supply is wrong
The shipped page says, and
CLAUDE.mdrecords, that there is no circulating-supplyfigure because
Balances::Locks,Holds,FreezesandReservesare all empty, socirculating would equal total issuance exactly and printing it would assert a
distinction the chain does not make.
The counting was right. The conclusion was wrong. The chain makes that distinction —
it just does not make it with locks.
Measured on mainnet at block 42,400 (
rpc1-mainnet.quantus.com), the single largestaccount holds 99.54% of every unit of balance on the chain:
6d6f646cis ASCIImodl; the account ismodlqvesting, which isPalletId(*b"qvesting")— the vesting pallet's own pot(
runtime/src/configs/mod.rs:606,impl pallet_vesting::Config for Runtimeat :669).This runtime's vesting is pot-based, not lock-based:
pallets/vestingholdsundistributed funds in its PalletId account and pays them out, rather than issuing them
to beneficiaries and freezing them with a
Balanceslock. That is precisely why thelock/hold/freeze maps read empty — and why reading "empty" as "nothing is withheld" got
it exactly backwards.
So:
Balances::TotalIssuanceThe page currently invites the reader to treat 5.68M as the supply in play. The number
in play is about 13,000 — a factor of 436. The "48 vesting schedules, a count not a
sum" note is the right instinct pointed at the wrong quantity: the sum that matters is
not the schedules, it is the pot, and the pot is a single storage read.
What to change
is not a judgement is that the page must not leave 5.68M standing unqualified.
A second, separate problem on the same page
The sum of all account free balances exceeds
TotalIssuance, and the gap grows:Genesis reconciles to the unit. Bisection puts the first divergence at block 4,800,
whose one non-inherent extrinsic is a 223 KiB bare call to pallet 20 call 3 —
Wormhole::verify_public_batch.The cause is deliberate and documented in the runtime.
Wormhole::credit_and_record(
pallets/wormhole/src/lib.rs:1348) credits an exit with<T::Currency as Unbalanced<_>>::increase_balance, notMutate::mint_into. Onlymint_intofollows the credit withset_total_issuance;increase_balancewrites theaccount and leaves issuance alone. The pallet's own comment says why it must stay that
way —
mint_intowould emitMinted, andWormholeProofRecorderExtensionwoulddouble-record the leaf. The only
set_total_issuancein the pallet is a subtraction,for the fee burn (:1001).
So a wormhole exit credits a spendable balance while the note's original account keeps
its balance, and issuance moves for neither.
TotalIssuanceis the honest supplyfigure; a sum of account balances is not, and the two diverge by the cumulative
value ever exited. Nothing on the site should ever add balances up and call the result
supply.
Verified single blocks reconcile (42401→42402 and 42405→42406 both match issuance delta
to balance delta exactly), so this is not a steady per-block leak — it is specific to
exit settlement.
The distribution phase, as specified, would describe the treasury
Building it now. The spec says "the share of issuance held by the top 1, 10 and
100" plus a Gini. Two measurements since this issue was written mean that, done
literally, it produces a number that is true and says nothing.
The top account is the vesting pot, holding 99.54%.
modlqvestingis thevesting pallet's own PalletId account. "Top 1 holds 99.5%" is a fact about an
undistributed reserve, not about how concentrated the economy is, and a Gini
computed with it in measures the same thing: it would sit near 0.99 forever and
move only when the pot pays out.
The denominator cannot be issuance. The sum of account balances exceeds
TotalIssuance— by 13,427 QTC at block 42,400 and growing — because a wormholeexit credits its destination without debiting the note's source. Shares of
issuance would therefore sum to more than 100%.
A large part of the tail is keyless. Mining rewards are paid to
derive_wormhole_address(preimage), which nothing can sign for, so thosebalances are cumulative receipt totals that can only rise (#19). Concentration
across them partly measures who mined most, not who holds most.
What gets built instead
excess over issuance explained rather than hidden.
shares and Gini are computed over everything else — labelled as being outside
the pot every time they appear.
are receipts, so a reader does not take the concentration figure for a
statement about wealth.
Cached on a TTL like
cached_roles, fed by a newstate_queryStorageAtinRpcClient— the client does not have one yet, which is why this was alwaysthe second phase.