← Live supply
Methodology

How ETH supply is calculated.

The homepage is a live per-slot ledger. It starts from an audited supply and applies every supply-changing event through the latest fully accounted slot. Historical proofs check that running total against Ethereum state.

01

The live calculation

next supply =
  previous supply
+ issuance
− execution fee burn
− consensus penalties
− ETH destroyed by SELFDESTRUCT

Each slot is calculated incrementally; the account tree is reserved for historical audits. Deposits and withdrawals preserve total supply while moving ETH between execution and consensus.

In the live JSON, supply.checkpoint is the audited starting balance and supply.asOf is the newer slot reached by the live ledger. “Checkpoint” names the audit baseline; the ledger updates each slot.

02

How an audit baseline is assembled

Execution balance proof

full-state execution anchor
+ later PoW issuance and withdrawals
− base-fee and blob-fee burn
− proven SELFDESTRUCT destruction
= execution balance at target

The anchor fixes one complete execution state. Canonical supply-changing flows and exact balance changes carry it to a newer checkpoint.

State reconciliation

execution balances
+ all consensus balances
− deposits represented on both layers

Execution balances are rooted in a complete account-state sum and carried forward through exact canonical changes. All consensus balances means validator balances plus balances temporarily held in consensus queues. The deposit history identifies the amount represented on both layers.

Creates ETH

Genesis allocation, historical PoW rewards, Beacon rewards.

Destroys ETH

Base fees, blob fees, consensus penalties, and rare ETH destruction caused by SELFDESTRUCT.

Preserves ETH supply

Transfers, deposits, withdrawals, and ETH held in an account.

Fixed identifiers for the completed historical proof
Full-state cross-check
block 15,082,718
Cross-check state root
0x65561806919577c751f07dc2073a6569da9c8692dfb9eec0c9f83fd603cfe0e6
Pinned reconciliation
block 25,827,072 · slot 15,064,579
Pinned supply
121,983,554.794011437471544651 ETH
Execution proof SHA-256
91ac1e5f3d424fdca66a3dde1baa488ba49b0de7ced216462504c21ac1594148
Difference between both calculations
0 wei
03

Independent validations

Each validation compares the same quantity through independent data paths.

Historical flows vs full execution state

Side A: canonical genesis allocation and every PoW reward, adjusted by every fee burn and proven historical destruction through block 15,082,718.

Side B: an independent enumeration and sum of all 176,496,428 execution accounts at that block's state root.

Cadence: one full-state validation at block 15,082,718, followed by exact per-slot flow roll-forward.

Result: both produce 118,908,973.575220938641041929 ETH; difference 0 wei.

Scope: this project ran both the state-enumeration and genesis-flow paths.

Protocol flows vs execution-balance changes

Side A: withdrawals and fee burn recomputed from canonical block fields.

Side B: the net balance change across every account touched by the block.

Third check: fork-aware traces and exact pre/post balances classify genuine SELFDESTRUCT destruction.

Cadence: Side A and Side B run for every canonical execution block. Trace and pre/post-state classification runs in explicit proof batches.

Result: every completed block closes to 0 wei or carries hash-bound classified destruction.

Scope: distinct Erigon data paths provide both views on one node; live warnings queue intervals for proof classification.

Execution deposits vs Beacon state

Side A: every execution-layer deposit event replayed in order, including independent BLS validation of first deposits.

Side B: Beacon validator balances, pending balances, and deposit index at the paired state root.

Third check: the fresh state-derived supply must equal the accumulated per-slot ledger from the previous checkpoint.

Cadence: once every 7 days. The scheduled run starts Saturday at 03:15 in the Europe/Rome timezone; host recovery triggers catch-up.

Latest completed run: Loading…

Result: every deposit is classified as accepted, pending, applied, or protocol-excluded; the categories reconcile with a 0-wei state-versus-ledger difference.

Scope: project-operated Erigon and Prysm provide separate execution and consensus views.

04

Reconciliation with other sources

Exact comparisons pair the same definition and canonical chain position. Timestamp-scoped sources retain timestamp-scoped observations. Every result is pinned to its stated reference, and each signed difference is source minus ethsupply.fyi.

Ultrasound.money ↗

Reference point · block 25,827,072 · slot 15,064,579
Difference · −2,172.701908505456054551 ETH
Execution interval adjustment · blocks 19,012,619–19,013,080
−1,933.701908505456054551 ETH
First-deposit accounting adjustment at the 2026 checkpoint
−239 ETH
Reconciliation remainder
0 wei

Result: Fully reconciled at the shared chain position.

Scope: The proof pins the 462-block interval to 15 January 2024, 13:36:47–15:09:11 UTC and reproduces its exact arithmetic. Source-side operational records determine infrastructure attribution.

Etherscan ↗

Reference point · API capture · 30 Aug 2026, 07:27:26 UTC
Difference · shared-position comparison requires a chain anchor
Captured API total
120,681,160.971774007880952888 ETH
Latest advancing consensus bucket
1 May 2025
Genesis precision adjustment
+0.00052 ETH
Frontier block reward adjustment
+5 ETH
Reconciliation remainder
0 wei

Result: The captured series combines continuing execution burn with a consensus component held at its 1 May 2025 value. The historical opening difference fully decomposes into genesis precision and one Frontier block reward.

Scope: A published block or slot establishes the shared position for an exact live difference.

Coin Metrics ↗

Reference point · 15 Sep 2022 execution/consensus boundary
Difference · +2,817.576878463104165098 ETH
Historical SELFDESTRUCT adjustment
+1.576878463104165098 ETH
First-deposit validity adjustment
−1 ETH
Consensus deduction adjustment in the 28 Mar 2024 history splice
+2,817 ETH
Reconciliation remainder
0 wei

Result: Fully reconciled at the shared 15 Sep 2022 boundary.

Scope: The pinned comparison uses the shared boundary. A current comparison pairs public constituent values with one chain position.

Other sources reviewed
CryptoQuantExact comparison pairs an authenticated numeric observation with a reproducible chain cutoff.
CoinMarketCap120,681,172 ETH at capture · integer-ETH precision.
Coinpedia120,681,247.23 ETH at capture · 0.01 ETH precision.
TradingViewGlassnode circulating-supply series; exact comparison pairs a numeric observation with one chain position.
CoinGecko120,681,171.50402609 ETH at capture · floating-response precision.
CoinPaprika120,232,214 ETH at capture · approximately −1.75 million ETH versus the reconciled family.
CoinLore122,374,665.71823 ETH at capture · aligned with a gross-issuance definition.
05

Public API schema

These five contracts expose every value used by the website. Fields ending in Wei or Gwei are base-10 integer strings, preserving exact values beyond JavaScript's numeric range. Timestamps are UTC Unix seconds.

TYPES Shared conventions · Scalars and shared objects

Units, precision, provenance, common totals, and response headers

type UInt = number;             // safe integer >= 0
type UnixSeconds = UInt;         // UTC Unix timestamp in seconds
type Revision = UInt;
type Decimal = string;           // /^(0|[1-9]\d*)$/
type SignedDecimal = string;     // /^-?\d+$/
type Wei = Decimal;
type SignedWei = SignedDecimal;
type Gwei = Decimal;
type Gas = Decimal;
type Hex20 = string;             // lowercase 0x + 40 hex characters
type Hex32 = string;             // lowercase 0x + 64 hex characters
type Range = "live" | "24h" | "7d" | "30d" | "retained";

type Availability = "exact" | "approximate" | "pending" | "unavailable";
type ValueKind = "observed" | "derived" | "modeled";

interface DataValue {
  value: string | null;
  status: Availability;
  kind: ValueKind;
  asOf: UnixSeconds | null;
  sources: string[];
}

interface PublicationWarning {
  code: string;
  amountWei: Wei;
  firstBlock: UInt;
  lastBlock: UInt;
}

interface HistoricalSummary {
  fromSlot: UInt;
  toSlot: UInt;
  fromTimestamp: UnixSeconds;
  toTimestamp: UnixSeconds;
  slots: UInt;
  blocks: UInt;
  issuanceWei: Wei;
  burnWei: Wei;
  baseFeeBurnWei: Wei;
  blobBaseFeeBurnWei: Wei;
  consensusPenaltiesWei: Wei;
  otherExecutionBurnWei: Wei;
  netWei: SignedWei;
  gasTargetTotal: Gas;
  offsetBaseFeeWei: Wei;
}

interface ApiError { error: string; }

// Every successful publication response includes:
// ETag, x-supply-sha256, x-supply-generated-at, x-supply-revision.
// x-supply-sha256 is the SHA-256 digest of the exact response bytes.
GET /api/live · SupplySnapshot

Current exact claim and live presentation inputs

interface IssuanceBreakdown {
  totalWei: DataValue;
  attestationSourceWei: DataValue;
  attestationTargetWei: DataValue;
  attestationHeadWei: DataValue;
  attestationInclusionWei: DataValue;
  syncCommitteeWei: DataValue;
  syncInclusionWei: DataValue;
  proposerSlashingWei: DataValue;
  attesterSlashingWei: DataValue;
  otherProposerWei: DataValue;
}

interface ConsensusPenaltyBreakdown {
  totalWei: DataValue;
  attestationSourceWei: DataValue;
  attestationTargetWei: DataValue;
  inactivityWei: DataValue;
  syncCommitteeWei: DataValue;
  initialSlashingWei: DataValue;
  correlationSlashingWei: DataValue;
}

interface BurnBreakdown {
  totalWei: DataValue;
  baseFeeWei: DataValue;
  blobBaseFeeWei: DataValue;
  consensus: ConsensusPenaltyBreakdown;
  otherExecutionWei: DataValue;
}

interface LiveBlock {
  number: UInt;
  hash: Hex32;
  slot: UInt;
  timestamp: UnixSeconds;
  gas: { used: Gas; target: Gas; max: Gas };
  baseFeePerGas: Wei;
  blobs: { used: UInt; target: UInt; max: UInt; gasUsed: Gas };
  blobBaseFee: Wei;
  burn: {
    baseFeeWei: Wei;
    blobBaseFeeWei: Wei;
    feeBurnWei: Wei;
    otherWei: Wei | null;
  };
  proposerIssuance: {
    totalGwei: Gwei | null;
    attestationsGwei: Gwei | null;
    syncAggregateGwei: Gwei | null;
    proposerSlashingsGwei: Gwei | null;
    attesterSlashingsGwei: Gwei | null;
  };
  accounting?: {
    issuanceWei: Wei;
    feeBurnWei: Wei;
    consensusPenaltiesWei: Wei;
    otherBurnWei: Wei;
    totalBurnWei: Wei;
    netWei: SignedWei;
  };
}

interface CurvePoint {
  activeStakeGwei: Gwei;
  annualIssuanceWei: Wei;
}

interface SupplySnapshot {
  schemaVersion: 1;
  revision: Revision;
  generatedAt: UnixSeconds;
  chainId: 1;
  head: {
    block: UInt | null;
    slot: UInt | null;
    timestamp: UnixSeconds | null;
  };
  finalized: {
    block: UInt | null;
    epoch: UInt | null;
    slot: UInt | null;
  };
  justified?: { epoch: UInt | null; slot: UInt | null };
  protocol: {
    secondsPerSlot: UInt;
    slotsPerEpoch: UInt;
    executionFork: string;
    consensusFork: string;
    gasElasticityMultiplier: UInt;
    blobGasPerBlob: UInt;
    blobsPerBlock: { target: DataValue; max: DataValue };
  };
  supply: {
    totalWei: DataValue;
    checkpoint: {
      block: UInt;
      slot: UInt;
      timestamp: UnixSeconds;
      executionHash: Hex32;
      promotedAt: UnixSeconds | null;
    } | null;
    asOf: {
      block: UInt;
      slot: UInt;
      epoch: UInt;
      timestamp: UnixSeconds;
    } | null;
    finalizedTotalWei: DataValue;
    finalizedAsOf: {
      block: UInt;
      slot: UInt;
      epoch: UInt;
      timestamp: UnixSeconds;
    } | null;
    executionNetIssuanceWei: DataValue;
    consensusNetIssuanceWei: DataValue;
  };
  accounting: {
    interval: "finalized_epoch";
    epoch: UInt | null;
    targetEpoch: UInt | null;
    attestationDutyEpoch: UInt | null;
    issuance: IssuanceBreakdown;
    burn: BurnBreakdown;
    netWei: DataValue;
    offsetBaseFeeWei: DataValue;
    gasTarget: DataValue;
  };
  staking: {
    activeBalanceGwei: DataValue;
    effectiveBalanceGwei: DataValue;
    activeValidators: DataValue;
    pendingDeposits: {
      validators: DataValue;
      balanceGwei: DataValue;
      slotZeroBalanceGwei: DataValue;
    };
    scheduledActivations: { validators: DataValue; balanceGwei: DataValue };
    scheduledExits: { validators: DataValue; balanceGwei: DataValue };
    pendingPartialWithdrawals: { requests: DataValue; balanceGwei: DataValue };
    pendingConsolidations: { requests: DataValue; balanceGwei: DataValue };
    churn: { activationExitGwei: DataValue; consolidationGwei: DataValue };
  };
  issuanceCurve: {
    status: Availability;
    currentStakeGwei: Gwei | null;
    assumption: string;
    points: CurvePoint[];
    sources: string[];
  };
  liveBlocks: LiveBlock[];
  history?: HistoryPoint[];
  warnings: Array<PublicationWarning & { code: "other_execution_burn" }>;
}

GET /api/live?afterRevision=<Revision>
200 SupplySnapshot
204 empty body when afterRevision equals the current revision
304 empty body when If-None-Match matches
400 ApiError when revision validation fails
503 ApiError during live publication readiness
GET /api/history?range=… · HistoricalSnapshot

Complete chart inputs and incremental live history

interface HistoryPoint {
  epoch: UInt;
  attestationDutyEpoch: UInt | null;
  timestamp: UnixSeconds;
  blocks: UInt;
  supplyWei: Wei | null;
  issuanceWei: Wei | null;
  attestationIssuanceWei: Wei | null;
  syncCommitteeIssuanceWei: Wei | null;
  proposerIssuanceWei: Wei | null;
  attestationSourceIssuanceWei: Wei | null;
  attestationTargetIssuanceWei: Wei | null;
  attestationHeadIssuanceWei: Wei | null;
  attestationInclusionIssuanceWei: Wei | null;
  syncInclusionIssuanceWei: Wei | null;
  proposerSlashingIssuanceWei: Wei | null;
  attesterSlashingIssuanceWei: Wei | null;
  otherProposerIssuanceWei: Wei | null;
  burnWei: Wei | null;
  baseFeeBurnWei: Wei;
  blobBaseFeeBurnWei: Wei;
  consensusPenaltiesWei: Wei | null;
  attestationSourcePenaltyWei: Wei | null;
  attestationTargetPenaltyWei: Wei | null;
  inactivityPenaltyWei: Wei | null;
  syncCommitteePenaltyWei: Wei | null;
  initialSlashingPenaltyWei: Wei | null;
  correlationSlashingPenaltyWei: Wei | null;
  otherExecutionBurnWei: Wei | null;
  netWei: SignedWei | null;
  offsetBaseFeeWei: Wei | null;
  averageBaseFeePerGasWei: Wei | null;
  gasUsed: Gas;
  gasTarget: Gas;
  gasMax: Gas;
  blobsUsed: UInt;
  blobsTarget: UInt;
  blobsMax: UInt;
}

interface SlotHistoryPoint {
  slot: UInt;
  epoch: UInt;
  block: UInt | null;
  blockKnown: boolean;
  finalized: boolean;
  timestamp: UnixSeconds;
  attestationDutyEpoch: UInt | null;
  supplyWei: Wei | null;
  issuanceWei: Wei | null;
  attestationIssuanceWei: Wei | null;
  syncCommitteeIssuanceWei: Wei | null;
  proposerIssuanceWei: Wei | null;
  attestationSourceIssuanceWei: Wei | null;
  attestationTargetIssuanceWei: Wei | null;
  attestationHeadIssuanceWei: Wei | null;
  attestationInclusionIssuanceWei: Wei | null;
  syncInclusionIssuanceWei: Wei | null;
  proposerSlashingIssuanceWei: Wei | null;
  attesterSlashingIssuanceWei: Wei | null;
  otherProposerIssuanceWei: Wei | null;
  burnWei: Wei | null;
  baseFeeBurnWei: Wei | null;
  blobBaseFeeBurnWei: Wei | null;
  consensusPenaltiesWei: Wei | null;
  attestationSourcePenaltyWei: Wei | null;
  attestationTargetPenaltyWei: Wei | null;
  inactivityPenaltyWei: Wei | null;
  syncCommitteePenaltyWei: Wei | null;
  initialSlashingPenaltyWei: Wei | null;
  correlationSlashingPenaltyWei: Wei | null;
  otherExecutionBurnWei: Wei | null;
  netWei: SignedWei | null;
  offsetBaseFeeWei: Wei | null;
  baseFeePerGasWei: Wei | null;
  gasUsed: Gas | null;
  gasTarget: Gas | null;
  gasMax: Gas | null;
  blobsUsed: UInt | null;
  blobsTarget: UInt | null;
  blobsMax: UInt | null;
  blobFloorBurnWei?: Wei | null;
  blobCongestionBurnWei?: Wei | null;
  fromSlot?: UInt;
  toSlot?: UInt;
  fromTimestamp?: UnixSeconds;
  toTimestamp?: UnixSeconds;
  blocks?: UInt;
}

interface StakingHistoryPoint {
  epoch: UInt;
  slot: UInt;
  timestamp: UnixSeconds;
  activeBalanceGwei: Gwei | null;
  effectiveBalanceGwei: Gwei | null;
  activeValidators: Decimal | null;
  blsActiveValidators: UInt | null;
  executionActiveValidators: UInt | null;
  compoundingActiveValidators: UInt | null;
  otherActiveValidators: UInt | null;
  blsEffectiveBalanceGwei: Gwei | null;
  executionEffectiveBalanceGwei: Gwei | null;
  compoundingEffectiveBalanceGwei: Gwei | null;
  otherEffectiveBalanceGwei: Gwei | null;
  pendingDeposits: UInt;
  pendingDepositsGwei: Gwei;
  scheduledActivations: UInt;
  scheduledActivationsGwei: Gwei;
  scheduledExits: UInt;
  scheduledExitsGwei: Gwei;
  partialWithdrawals: UInt;
  partialWithdrawalsGwei: Gwei;
  consolidations: UInt;
  consolidationsGwei: Gwei;
  activationExitChurnGwei: Gwei | null;
  consolidationChurnGwei: Gwei | null;
  entryQueueWaitSeconds: UInt | null;
  exitQueueWaitSeconds: UInt | null;
}

interface QueueWaitHistoryPoint {
  epoch: UInt;
  slot: UInt;
  timestamp: UnixSeconds;
  entryQueueWaitSeconds: UInt | null;
  exitQueueWaitSeconds: UInt | null;
}

interface HistoricalSnapshot {
  schemaVersion: 1;
  revision: Revision;
  generatedAt: UnixSeconds;
  range: Range;
  interval?: "slot" | "hour" | "3hour" | "day" | "epoch" |
    "2epochs" | "10epochs" | "30epochs" | "225epochs";
  intervalEpochs?: UInt;
  intervalSlots?: UInt;
  coverage?: {
    fromSlot: UInt;
    toSlot: UInt;
    slots: UInt;
    blocks: UInt;
    missedSlots: UInt;
    complete: true;
  };
  slots: SlotHistoryPoint[];
  epochs: HistoryPoint[];
  staking: StakingHistoryPoint[];
  queueWaits?: QueueWaitHistoryPoint[];
  validatorTypes?: StakingHistoryPoint[];
  missedSlotPositions?: Array<{
    position: UInt;
    slots: UInt;
    missedSlots: UInt;
  }>;
  summary?: HistoricalSummary;
  warnings?: PublicationWarning[];
  partial?: boolean;
  baseRevision?: Revision;
  dropBeforeSlot?: UInt;
  dropBeforeEpoch?: UInt;
  dropBeforeStakingSlot?: UInt;
  dropBeforeQueueWaitSlot?: UInt;
  dropBeforeValidatorTypeSlot?: UInt;
}

GET /api/history?range=<Range>&afterRevision=<Revision>
200 HistoricalSnapshot; live may return an incremental snapshot with baseRevision
204 empty body when live afterRevision equals the current revision
304 empty body when If-None-Match matches
400 ApiError when range or revision validation fails
503 ApiError during selected-range publication readiness

range=live uses afterRevision for incremental delivery.
Static ranges return their complete current document.
GET /api/tracked · TrackedRangeSnapshot

Retained cumulative accounting

interface TrackedRangeSnapshot {
  schemaVersion: 1;
  revision: Revision;
  generatedAt: UnixSeconds;
  range: "retained";
  summary: HistoricalSummary;
  warnings: PublicationWarning[];
  finalizedToSlot?: UInt;
  liveTailSlots?: UInt;
}

GET /api/tracked?afterRevision=<Revision>
200 TrackedRangeSnapshot
204 empty body when afterRevision equals the current revision
304 empty body when If-None-Match matches
400 ApiError when revision validation fails
503 ApiError during retained-summary publication readiness
GET /api/gas-guzzlers · GasManifest | GasLeaderboard

Capability discovery and contract-level burn attribution

type LabelSource =
  "kleros" | "onchain" | "etherscan-snapshot" | "trustwallet" | "sourcify";
type LabelKind = "curated" | "token" | "derived" | "verified-contract";

interface AddressLabel {
  name: string;
  source: LabelSource;
  kind: LabelKind;
}

interface GasCoverage {
  fromSlot: UInt;
  toSlot: UInt;
  fromBlock: UInt;
  toBlock: UInt;
  fromTimestamp: UnixSeconds;
  toTimestamp: UnixSeconds;
  blocks: UInt;
  finalized: boolean;
}

interface GasLeaderboard {
  schemaVersion: 2;
  revision: Revision;
  generatedAt: UnixSeconds;
  range: Range;
  metric: "base-fee-burn";
  attribution: "exclusive-code-address";
  burnAttribution: "receipt-base-fee-pro-rata-exclusive-code-gas";
  coverage: GasCoverage;
  reconciliation: {
    rootGas: Gas;
    attributedGas: Gas;
    complete: true;
    rootBurnWei: Wei;
    attributedBurnWei: Wei;
    burnComplete: true;
  };
  specialGas: { precompiles: Gas; failedCreates: Gas };
  specialBurnWei: {
    precompiles: Wei;
    failedCreates: Wei;
    noExecution: Wei;
  };
  entries: Array<{                // at most 50; ranks are contiguous from 1
    rank: UInt;
    address: Hex20;
    kind: "contract";
    gas: Gas;
    calls: UInt;
    transactions: UInt;
    shareBps: UInt;
    burnWei: Wei;
    label?: AddressLabel;
  }>;
}

interface GasManifest {
  schemaVersion: 2;
  revision: Revision;
  generatedAt: UnixSeconds;
  ranges: Array<{
    range: Range;
    revision: Revision;
    generatedAt: UnixSeconds;
    coverage: GasCoverage;
  }>;
}

GET /api/gas-guzzlers
200 GasManifest containing ranges with completed independent readiness

GET /api/gas-guzzlers?range=<Range>
200 GasLeaderboard
404 text "Not found" when range falls outside Range
503 ApiError during independent range readiness
WS /api/stream?v=2 · PublicationEvent

Atomic live WebSocket frames

interface PublicationEvent {
  schemaVersion: 1;
  type: "publication";
  revision: Revision;
  generatedAt: UnixSeconds;
  live: SupplySnapshot | LiveSnapshotDelta;
  history: HistoricalSnapshot | HistoryRecovery;
  tracked: TrackedRangeSnapshot;
}

type LiveSnapshotDelta = Omit<SupplySnapshot, "issuanceCurve" | "liveBlocks"> & {
  baseRevision: Revision;
  liveBlocks: LiveBlock[];          // changed block slots only
  liveBlocksDropBeforeSlot: UInt;
  issuanceCurve?: SupplySnapshot["issuanceCurve"];
};

interface HistoryRecovery {
  schemaVersion: 1;
  revision: Revision;
  generatedAt: UnixSeconds;
  range: "live";
  recoveryRequired: true;
}

WebSocket wss://ethsupply.fyi/api/stream?v=2
101 switches protocols and immediately sends the latest PublicationEvent
426 text response requiring a WebSocket upgrade

history is one of:
- a compact partial live HistoricalSnapshot for a new connection;
- an incremental HistoricalSnapshot carrying baseRevision;
- HistoryRecovery, which instructs the client to refetch /api/history?range=live.

The first event contains a complete SupplySnapshot. Later version-two events
carry LiveSnapshotDelta and preserve unchanged curve/block-window data from the
declared baseRevision. Unversioned /api/stream remains the full-event
compatibility protocol for tabs opened before this version.

Client text "ping" receives text "pong" automatically.

HTTP endpoints accept GET and HEAD. JSON responses include an x-supply-sha256 header equal to the SHA-256 of their exact bytes, plus revision and generation time.

curl -sS -D headers https://ethsupply.fyi/api/live -o live.json
shasum -a 256 live.json
grep x-supply-sha256 headers
Independent reproduction steps
  1. Pin the published block, slot, hashes, and state roots.Fix one canonical chain position before doing arithmetic.
  2. Rebuild execution balances.Enumerate the root-bound state and replay issuance, withdrawals, fee burn, and proven destruction.
  3. Rebuild consensus balances.Sum every validator and consensus-queue balance, then replay accepted deposit events.
  4. Recompute both equations.The state calculation and genesis-to-slot ledger must produce the same wei.