A network page: the figures an analyst needs to judge ecosystem health #17

Closed
opened 2026-09-14 05:33:02 +00:00 by grenade · 2 comments
Owner

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:

Balances::TotalIssuance            5,682,897.573 QTC
Balances::InactiveIssuance         0
MiningRewards::CollectedFees       9,936,277,339
QPoW::CurrentDifficulty            146,055,895,096,523
ZkTree::LeafCount                  82,192
Vesting::NextScheduleId            48
TechReferenda::ReferendumCount     0
ReversibleTransfers::NextTransactionId  0

Map sizes, counted by enumeration on mainnet:

System::Account       1,914 keys     <- accounts that exist, a chain fact
Vesting::Schedules       48 keys
Balances::Locks           0 keys
Balances::Holds           0 keys
Balances::Freezes         0 keys

state_queryStorageAt exists 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 /genesis already 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 custom Vesting does, 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. /calls has 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.

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`: ``` Balances::TotalIssuance 5,682,897.573 QTC Balances::InactiveIssuance 0 MiningRewards::CollectedFees 9,936,277,339 QPoW::CurrentDifficulty 146,055,895,096,523 ZkTree::LeafCount 82,192 Vesting::NextScheduleId 48 TechReferenda::ReferendumCount 0 ReversibleTransfers::NextTransactionId 0 ``` **Map sizes**, counted by enumeration on mainnet: ``` System::Account 1,914 keys <- accounts that exist, a chain fact Vesting::Schedules 48 keys Balances::Locks 0 keys Balances::Holds 0 keys Balances::Freezes 0 keys ``` **`state_queryStorageAt` exists** 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 `/genesis` already 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 custom `Vesting` does, 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. `/calls` has 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.
Author
Owner

Correction: the page's reason for omitting circulating supply is wrong

The shipped page says, and CLAUDE.md records, that there is no circulating-supply
figure because Balances::Locks, Holds, Freezes and Reserves are all empty, so
circulating 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 largest
account holds 99.54% of every unit of balance on the chain:

0x6d6f646c7176657374696e6700…00   5,669,940.001 QTC   nonce 0   99.54%

6d6f646c is ASCII modl; the account is modlqvesting, which is
PalletId(*b"qvesting") — the vesting pallet's own pot
(runtime/src/configs/mod.rs:606, impl pallet_vesting::Config for Runtime at :669).

This runtime's vesting is pot-based, not lock-based: pallets/vesting holds
undistributed funds in its PalletId account and pays them out, rather than issuing them
to beneficiaries and freezing them with a Balances lock. That is precisely why the
lock/hold/freeze maps read empty — and why reading "empty" as "nothing is withheld" got
it exactly backwards.

So:

QTC
Balances::TotalIssuance 5,682,968.964
held in the vesting pot 5,669,940.001
issuance outside the pot 13,028.963

The 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

  • Report the vesting pot as its own line, by name, with its balance.
  • Report issuance-minus-pot. Whether that is called "circulating" is a judgement; what
    is not a judgement is that the page must not leave 5.68M standing unqualified.
  • Drop the claim that the chain draws no distinction. It draws it with a pot.

A second, separate problem on the same page

The sum of all account free balances exceeds TotalIssuance, and the gap grows:

block      0   issuance 5,670,000.001   Σ free 5,670,000.001   delta      +0.000
block  4,000   issuance 5,671,226.351   Σ free 5,671,226.351   delta      +0.000
block  4,800   issuance 5,671,471.???   Σ free …               delta    +111.830   <- first
block 10,000   issuance 5,673,063.441   Σ free 5,674,840.771   delta  +1,777.330
block 20,000   issuance 5,676,120.137   Σ free 5,682,439.327   delta  +6,319.190
block 30,000   issuance 5,679,174.300   Σ free 5,688,926.540   delta  +9,752.240
block 42,400   issuance 5,682,958.266   Σ free 5,696,380.896   delta +13,422.630

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, not Mutate::mint_into. Only
mint_into follows the credit with set_total_issuance; increase_balance writes the
account and leaves issuance alone. The pallet's own comment says why it must stay that
way — mint_into would emit Minted, and WormholeProofRecorderExtension would
double-record the leaf. The only set_total_issuance in 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. TotalIssuance is the honest supply
figure; 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.

## Correction: the page's reason for omitting circulating supply is wrong The shipped page says, and `CLAUDE.md` records, that there is no circulating-supply figure because `Balances::Locks`, `Holds`, `Freezes` and `Reserves` are all empty, so circulating 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 largest account holds **99.54%** of every unit of balance on the chain: ``` 0x6d6f646c7176657374696e6700…00 5,669,940.001 QTC nonce 0 99.54% ``` `6d6f646c` is ASCII `modl`; the account is `modlqvesting`, which is `PalletId(*b"qvesting")` — the vesting pallet's own pot (`runtime/src/configs/mod.rs:606`, `impl pallet_vesting::Config for Runtime` at :669). This runtime's vesting is **pot-based, not lock-based**: `pallets/vesting` holds undistributed funds in its PalletId account and pays them out, rather than issuing them to beneficiaries and freezing them with a `Balances` lock. That is precisely why the lock/hold/freeze maps read empty — and why reading "empty" as "nothing is withheld" got it exactly backwards. So: | | QTC | |---|---| | `Balances::TotalIssuance` | 5,682,968.964 | | held in the vesting pot | 5,669,940.001 | | **issuance outside the pot** | **13,028.963** | The 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 - Report the vesting pot as its own line, by name, with its balance. - Report issuance-minus-pot. Whether that is called "circulating" is a judgement; what is not a judgement is that the page must not leave 5.68M standing unqualified. - Drop the claim that the chain draws no distinction. It draws it with a pot. ### A second, separate problem on the same page The sum of all account free balances **exceeds `TotalIssuance`**, and the gap grows: ``` block 0 issuance 5,670,000.001 Σ free 5,670,000.001 delta +0.000 block 4,000 issuance 5,671,226.351 Σ free 5,671,226.351 delta +0.000 block 4,800 issuance 5,671,471.??? Σ free … delta +111.830 <- first block 10,000 issuance 5,673,063.441 Σ free 5,674,840.771 delta +1,777.330 block 20,000 issuance 5,676,120.137 Σ free 5,682,439.327 delta +6,319.190 block 30,000 issuance 5,679,174.300 Σ free 5,688,926.540 delta +9,752.240 block 42,400 issuance 5,682,958.266 Σ free 5,696,380.896 delta +13,422.630 ``` 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`, **not** `Mutate::mint_into`. Only `mint_into` follows the credit with `set_total_issuance`; `increase_balance` writes the account and leaves issuance alone. The pallet's own comment says why it must stay that way — `mint_into` would emit `Minted`, and `WormholeProofRecorderExtension` would double-record the leaf. The only `set_total_issuance` in 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. **`TotalIssuance` is the honest supply figure; 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.
Author
Owner

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%. modlqvesting is the
vesting 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 wormhole
exit 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 those
balances 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

  • Denominator is the sum of counted balances, named as such, with the
    excess over issuance explained rather than hidden.
  • The pot is reported first and separately, then excluded, and the top-N
    shares and Gini are computed over everything else — labelled as being outside
    the pot every time they appear.
  • The page says that the tail includes keyless mining addresses whose balances
    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 new state_queryStorageAt in
RpcClient — the client does not have one yet, which is why this was always
the second phase.

## 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%.** `modlqvesting` is the vesting 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 wormhole exit 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 those balances 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 - Denominator is **the sum of counted balances**, named as such, with the excess over issuance explained rather than hidden. - The **pot is reported first and separately**, then excluded, and the top-N shares and Gini are computed over everything else — labelled as being outside the pot every time they appear. - The page says that the tail includes keyless mining addresses whose balances 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 new `state_queryStorageAt` in `RpcClient` — the client does not have one yet, which is why this was always the second phase.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: blackbeard/observer#17