docs/design/base-unit.md: where every amount lives (UTXO value, entry, mass view, coinbase and its payload, fees, script introspection, p2p, gRPC, RPC model, JSON and wasm, wallet, UTXO index, the exec bridge, pool accounting, pool software, app display, observer and public stats, the manifest), the u128 Amount type, the serialisation and versioning table (tx version 2 for the 16-byte value, a store schema version with the u64 legacy decode, two uint64 varints on the wire with the low word on the existing field number), the EVM side (1 IGN = 10^18 wei, the bridge the identity), the devnet unchanged at 8 with its digest unmoved, the display rule (8 visible digits), the hostile review (the u64 pool share overflow, the ramp, the 66-period table, the floor at the finer unit, the storage mass constant at 10^22, dust and the relay floor, MAX_SOMPI, KIP-10 script numbers, JavaScript precision, the wrong-unit peer, the half-widened binary, Postgres bigint), the measurement (+8 B per UTXO on disk, +17 B in memory, +6.4 B per output on the wire) with the consequences by tier, and phase B in ten commits with hours (26). Spec 2.5 carries the proposed Decided sentence and the 18-decimal rate; 06-open-items O-2.6 proposed decided with its gate B10; fud-ledger E22; fork-divergence row for the fork commits (3158571c, fa61e035, fcd6b6e9, 6d5f2488 on the box mirror, branch decimals); bench-log "Base unit widening cost"; public-stats unit note; ledger-decisions row 5 lane state. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
11 KiB
Public stats API
5 October 2026. Two JSON endpoints on the site for profitability sites, pool software and anyone who wants the
network numbers without running a node: /api/stats and /api/supply. WhatToMine's listing form asks for an
explorer or pool with an API, the reward halving schedule and a source to fetch total coins from; this is that source.
A third endpoint, /api/explorer, feeds the explorer pages (docs/plans/explorer.md).
Both are served by Vercel functions (site/api/stats.mjs, site/api/supply.mjs) that read what the devnet observer
(tools/observer/observer.mjs) wrote to Neon; no secret is involved beyond the database connection the site already
holds. Cached 10 s at the edge (Cache-Control: public, max-age=10, s-maxage=10), CORS open (Access-Control-Allow-Origin: *),
GET only. A failed read answers 500 with {ok: false, error} and Cache-Control: no-store.
The contract is the FIELDS list exported by each handler. site/api/public-stats.test.mjs checks a fixture against
it without a database, and tools/ci/public-api-check.mjs <url> checks a deployment (CI runs it against
https://igneum.network on master).
/api/stats
| Field | Meaning | Source |
|---|---|---|
network, chain_id, node_version |
Network name, EVM chain id (4461 mainnet, 4462 testnet, 4463 devnet, design 8.1), the node's version | observer live_state |
algorithm |
The lottery hash, named | fixed text |
stale, age_s, observer_updated_at |
stale when the observer has not written for 30 s; treat every number as last known then |
observer |
height |
The chain block number (the EVM block number): the number of the newest chain block the observer has a shard plan for | live_blocks.number |
block_count, header_count |
Every DAG block the node holds | getBlockDagInfo |
daa, blue_score |
DAA score and blue score of the newest block | live_blocks, getSinkBlueScore |
difficulty |
The node's difficulty (target per block) | getBlockDagInfo |
hashrate, hashrate_unit, hashrate_source |
H/s: the node's estimateNetworkHashesPerSecond over 1,000 blocks, else blue work added per second over 10 min |
observer |
block_time_target_s, block_time_measured_s |
1 s by design (spec 2.1); 60 / DAG blocks in the last 60 s | observer |
blocks_per_day_target, blocks_per_day_measured |
86,400; the last hour's DAG blocks x 24 (null until the observer has an hour) | observer |
block_reward |
E(daa) of spec 2.5 at the newest DAA score: sompi (8 decimals), ign, the 80% miner_ign and 20% proving_pool_ign, ramp_factor, halving_period, next_halving_daa, next_halving_in_s |
site/lib/emission.mjs |
last_block |
Hash, time, age, blue score, DAA, coinbase address, vote key id, EVM transaction count, whether it is a chain block | live_blocks |
finality |
Finality v2: active, the latest locked checkpoint index and blue score | observer |
peers, mempool, miners_10m |
Connected peers, mempool size, distinct vote keys in 10 min (a card runs several) | observer |
Note for a profitability calculator: block_reward is per blue block merged; at the 1 block per second target that is
also the reward per DAA second. The 20% proving-pool part is paid to provers, not to the miner of the block, so a
miner's expected income per block is miner_ign. During the 30-day launch ramp the reward climbs from 10% to 100%
of the schedule (ramp_factor); /api/supply shows where the ramp stands.
Example, the devnet on 5 October 2026 (through the local preview against a test observer, so block_time_measured_s
reflects a one-minute window):
{
"ok": true,
"now": "2026-10-05T19:32:09.321Z",
"network": "igneum-devnet",
"chain_id": 4463,
"node_version": "2.1.0",
"algorithm": "Igneum lottery hash: random-program GPU hash, new program every hour, generator v2 (docs/spec/01-lottery-hash.md)",
"stale": false,
"age_s": 0.9,
"height": 82145,
"block_count": 126358,
"header_count": 126358,
"daa": 126357,
"blue_score": 123504,
"difficulty": 125543017.00697394,
"hashrate": 258756880,
"hashrate_unit": "H/s",
"hashrate_source": "the node's estimateNetworkHashesPerSecond over a 1,000-block window; blue work added per second over 10 min when the node refuses the window",
"block_time_target_s": 1,
"block_time_measured_s": 0.952,
"blocks_per_day_target": 86400,
"blocks_per_day_measured": 14040,
"block_reward": {
"sompi": "455909062",
"ign": "4.55909062",
"miner_ign": "3.6472725",
"proving_pool_ign": "0.91181812",
"split": "80% block producer, 20% proving pool",
"daa_used": 126357,
"ramp_factor": 0.143874,
"halving_period": 0,
"next_halving_daa": 63115200,
"next_halving_in_s": 62988843
},
"last_block": {
"hash": "bbec3139d3f38e3517716374707998e77f536a67813edfb619c5bed93a5779ab",
"time": "2026-10-05T19:32:06.157Z",
"ts_ms": 1791228726157,
"age_s": 3.2,
"blue_score": 123504,
"daa": 126357,
"miner": "igneumdev:qrt8nzgrghr2a2xuc7lstzclcnt3n632d2chhc946rphkc6flcyswvkrym8s4",
"miner_id": "7b8ef6fd",
"tx_count": 0,
"chain": true
},
"finality": {
"active": true,
"latest_locked_index": 4116,
"latest_locked_blue_score": 123480,
"chain_id": "igneum-devnet"
},
"peers": 4,
"mempool": 0,
"miners_10m": 21,
"observer_updated_at": "2026-10-05T19:32:08.394726+00:00",
"source": "tools/observer reading one node every 2 s; reward from docs/spec/02-consensus.md 2.5 at the node's DAA score"
}
/api/supply
| Field | Meaning |
|---|---|
unit |
IGN; the devnet's coinbase pays in 8-decimal units and the EVM shows 18; the testnet and mainnet unit is 18 on both sides (O-2.6, proposed Decided 6 October 2026, docs/design/base-unit.md), so decimals_consensus reads the network's genesis parameter |
daa |
The newest DAA score the observer stored |
max_supply_ign |
4,000,000,000, the hard cap (spec 2.5, no tail emission: spec 5.10) |
circulating_ign, circulating_sompi |
Minted so far by the rule: E(t) summed over every DAA second from 0 to daa, exact (floor sum, mintedByRule) |
minted_at_end_ign, never_minted_ign |
What the schedule reaches when the per-second rate hits 0 (period 32), and the part of the cap the ramp and the floors never mint |
emission_per_second_ign, block_reward_ign |
E(daa) now |
halving |
Interval 63,115,200 DAA s (two years), current period, the next halving's DAA score, seconds to it, a date estimate at one DAA second per second |
ramp |
10% at genesis to 100% at DAA 2,592,000 (30 days), the factor now, whether it is complete |
schedule |
33 rows: period, start and end DAA, years from genesis, IGN per second, IGN per block at 1 BPS, minted by the end of the period, share of the cap |
check |
The observer's hourly comparison of the chain against the rule over its newest 500 blocks: rule_match counts blocks whose coinbase payload declares exactly E(daa); sum_match counts blocks whose coinbase outputs equal the declared subsidies of the blocks they merge; examples names mismatches |
rule, source, note |
The formula, where it lives, and the caveat: the chain pays per block merged, so a block rate above target mints above the schedule for as long as it lasts |
Example (schedule cut to five rows here):
{
"ok": true,
"now": "2026-10-05T19:32:09.374Z",
"network": "igneum-devnet",
"chain_id": 4463,
"unit": {
"symbol": "IGN",
"decimals_consensus": 8,
"decimals_evm": 18,
"note": "the coinbase pays in 8-decimal units (open item O-2.6 keeps Kaspa's SOMPI_PER_KASPA); the EVM shows the same amount at 18 decimals"
},
"daa": 126357,
"max_supply_ign": "4000000000",
"circulating_ign": "488236.39686436",
"circulating_sompi": "48823639686436",
"minted_at_end_ign": "3963038988.86765648",
"never_minted_ign": "36961011.13234352",
"emission_per_second_ign": "4.55909062",
"block_reward_ign": "4.55909062",
"halving": {
"interval_daa_s": 63115200,
"interval_years": 2,
"period": 0,
"next_halving_daa": 63115200,
"next_halving_in_s": 62988843,
"next_halving_estimate": "2028-10-03T20:26:12.374Z",
"estimate_note": "the estimate assumes one DAA second per wall-clock second from now"
},
"ramp": {
"start_percent": 10,
"length_daa_s": 2592000,
"length_days": 30,
"factor_now": 0.143874,
"complete": false,
"remaining_s": 2465643,
"withheld_ign": "36961011.13234352",
"withheld_note": "the ramp withholds about 37 million IGN that are never minted; integer floors withhold the rest (spec 2.5)"
},
"schedule": [
{
"period": 0,
"start_daa": 0,
"end_daa": 63115200,
"years_from_genesis": "0 to 2",
"per_second_ign": "31.68808781",
"per_block_ign_at_1bps": "31.68808781",
"minted_by_end_ign": "1963038999.85152848",
"share_of_cap_by_end": 49.0759
},
{
"period": 1,
"start_daa": 63115200,
"end_daa": 126230400,
"years_from_genesis": "2 to 4",
"per_second_ign": "15.8440439",
"per_block_ign_at_1bps": "15.8440439",
"minted_by_end_ign": "2963038999.40880848",
"share_of_cap_by_end": 74.0759
},
{
"period": 2,
"start_daa": 126230400,
"end_daa": 189345600,
"years_from_genesis": "4 to 6",
"per_second_ign": "7.92202195",
"per_block_ign_at_1bps": "7.92202195",
"minted_by_end_ign": "3463038999.18744848",
"share_of_cap_by_end": 86.5759
},
"... 29 more rows ...",
{
"period": 32,
"start_daa": 2019686400,
"end_daa": 2082801600,
"years_from_genesis": "64 to 66",
"per_second_ign": "0",
"per_block_ign_at_1bps": "0",
"minted_by_end_ign": "3963038988.86765648",
"share_of_cap_by_end": 99.0759
}
],
"check": {
"bps": 1,
"sampled": 470,
"examples": [],
"sum_match": 466,
"checked_at": "2026-10-05T19:30:28.385Z",
"rule_match": 470,
"sum_skipped": 4,
"sum_mismatch": 0,
"rule_mismatch": 0
},
"rule": "E(t) = ramp(t) * floor(10^9 * UNIT / 31,557,600) >> floor(t / 63,115,200); ramp(t) = min(1, 1/10 + 9/10 * t / 2,592,000); t = DAA score / bps, bps = 1",
"source": "docs/spec/02-consensus.md 2.5; vendor/igneum-node consensus/core/src/igneum.rs block_subsidy and launch_ramp; circulating = the rule summed over every DAA second from 0 to the node's DAA score (site/lib/emission.mjs mintedByRule, exact)",
"note": "circulating is the schedule at this DAA score. The chain pays E per blue block it merges and per red inside the DAA window, which tracks the schedule one block per DAA step; the devnet of 3 October 2026 ran 4.7x the schedule for eight minutes during a retarget lag (spec 2.5). check reports what the observer measured on the newest blocks."
}
/api/explorer
The explorer's own feed, cached 5 s: ?blocks=N[&before=ms] (latest blocks), ?block=hash, ?height=N,
?address=0x..|igneumdev:.., ?search=q. Shapes are in site/api/explorer.mjs; the pages are the reference client.
Balances need EXPLORER_EVM_RPC on the deployment (a public EVM JSON-RPC); without it balance.available is false
with the reason.