igneum/docs/api/public-stats.md
igneum-labs 303038a75d /api/stats gains proving (coverage_10m, provers, lag, verifier) from live_state.proving; the live page says whose verifier is off (reviewer C33)
A third party reading the public API could not see that proving coverage on the devnet is 2.7% of chain blocks with
one prover (13 of 476 in ten minutes at 22:33 UTC) while the homepage says every block is proven. The object is the one
/api/live reads, with coverage_10m = blocks_fully_proven_10m / blocks_10m and a note that the observer's node reads
the chain's payouts with its own verifier off. Documented with the live figures, in the contract test and the live check.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-05 22:35:21 +00:00

12 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
proving Proving v0, the same object /api/live and /live read: active, activation_daa, the last ten minutes' blocks_10m (chain blocks), blocks_fully_proven_10m (every shard proven and paid), shards_proven_10m, shards_paid_10m, provers_10m, median_proof_lag_s, coverage_10m (= fully proven / blocks), verifier (the observer node's own SP1 verifier, "Off" on the devnet: it reads the chain's payouts, not its own verification), pool_pending, note live_state.proving
peers, mempool, miners_10m Connected peers, mempool size, distinct vote keys in 10 min (a card runs several) observer

The proving object on the live devnet at 22:33 UTC on 5 October 2026 (reviewer C33): blocks_10m 476, blocks_fully_proven_10m 13, shards_paid_10m 13, provers_10m 1, median_proof_lag_s 46, coverage_10m 0.0273, verifier "Off", pool_pending 43. Coverage is what a third party should read before "every block is proven": tonight it is 2.7% of chain blocks with one prover, 46 s behind the tip.

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 coinbase pays in 8-decimal units (open item O-2.6), the EVM shows 18
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.