ODIN LIQUIDITY NETWORK · ANALYTICS · AGENT DATA PLANE

machine-readable · live-first with labelled fallback · v1 · 2026-07-29 · companion to /odinagents
[ 0 · MANIFEST ]
ODIN ANALYTICS · AGENT DATA PLANE v1 (2026-07-29)
The network's own measurements, packaged for machines. This page is the
analytics counterpart of the agent surface at
https://odinliquidity.network/odinagents - that page holds the trust anchor
(canonical registry, verification procedures, constraints, corpus); this one
holds the DATA: every metric the odinOS instruments measure, categorized,
with three layers per metric:

  1. #schema    what the metric IS - category, unit, basis, constraint, freshness
  2. #snapshot  a dated, block-stamped value (the honest fallback, never live-dressed)
  3. #recipes   the exact endpoints + formulas that recompute it live

TWO CONSUMPTION MODES
  static  - you fetched this page as HTML: use #schema + #snapshot + #recipes.
            Every recipe runs against open, keyless endpoints; nothing here
            needs this page to be up.
  browser - you drive a JavaScript context: this page fetches chain + market
            state ON LOAD, prints the result into #live, and exposes
            window.ODIN_ANALYTICS = {schema, snapshot, live, prov, refresh}.
            Call refresh() for a fresh read - the heartbeat is yours.

RULES (inherited from /odinagents - they travel with every field)
  - live | snapshot | implied are labelled and NEVER blended
  - a metric without its constraint is a misquote; keys here match
    /odinagents #constraints (apy, fees, lf, minLf, freeFloat, price, depth)
  - if this page and the chain disagree, the chain is right
  - freshness class "heartbeat" = recomputable now from open endpoints;
    "snapshot-only" = needs measured history - the k SERIES IS PUBLISHED
    (R9); the rest state their method so you can reproduce the measurement

SECTIONS: #manifest #schema #snapshot #recipes #live #livecode #selftest #boundaries
[ 1 · SCHEMA — THE METRIC CATALOG, CATEGORIZED ]
{
  "version": 1, "categories": ["supply","pools","float","price","flow","depth","engine","diversification"],
  "metrics": [
    { "id": "supply.max",            "cat": "supply", "unit": "ODIN", "freshness": "constant",  "def": "fixed maximum supply; totalSupply() always reads this - burns are held at addresses, never supply-reduced" },
    { "id": "supply.dead",           "cat": "supply", "unit": "ODIN", "freshness": "heartbeat", "def": "ODIN at the dead address (the transferred burn)" },
    { "id": "supply.pvalhallaBurn",  "cat": "supply", "unit": "ODIN", "freshness": "snapshot-only", "def": "ODIN accruing to the 33,333,333 pVAL locked at the dead address (the stranded burn); mechanism-derived from the pod ledger" },
    { "id": "supply.floors",         "cat": "supply", "unit": "ODIN", "freshness": "heartbeat", "def": "sum of k/cap over the 10 fully-diluted pairs (the un-buyable burn)", "constraint": "floor" },
    { "id": "supply.burned",         "cat": "supply", "unit": "ODIN", "freshness": "heartbeat", "def": "dead + pvalhallaBurn + floors - the canonical burn accounting" },
    { "id": "supply.circulating",    "cat": "supply", "unit": "ODIN", "freshness": "heartbeat", "def": "max - burned" },
    { "id": "pools.reserves",        "cat": "pools",  "unit": "per-pool {oR,pR,k}", "freshness": "heartbeat", "def": "reserves of the 16 locked pools; sink pool oR is pVALHALLA, convert at engine.podIndex" },
    { "id": "pools.lockedLiquidityUsd","cat": "pools","unit": "USD",  "freshness": "heartbeat", "def": "sum of locked-pool liquidity; dormant pools valued from chain reserves at price.odinUsd, labelled implied", "constraint": "provenance" },
    { "id": "pools.odinLocked",      "cat": "pools",  "unit": "ODIN", "freshness": "heartbeat", "def": "ODIN in the 16 pools: non-engine reserves + engine pVAL converted at podIndex, burned-stake share only" },
    { "id": "pools.dormant",         "cat": "pools",  "unit": "list", "freshness": "heartbeat", "def": "pools with no live market listing - DERIVED from feed absence, never a stored flag; quiet is not gone" },
    { "id": "float.floatBasis",      "cat": "float",  "unit": "ODIN", "freshness": "heartbeat", "def": "max - dead - pvalhallaBurn (the basis any where-does-it-sit split must total)", "constraint": "freeFloat" },
    { "id": "float.freeFloat",       "cat": "float",  "unit": "ODIN", "freshness": "heartbeat", "def": "floatBasis - odinLocked; NEVER circulating - odinLocked", "constraint": "freeFloat" },
    { "id": "float.lf",              "cat": "float",  "unit": "ratio","freshness": "heartbeat", "def": "2 x odinLocked / freeFloat - structural ownership gauge", "constraint": "lf" },
    { "id": "float.minLf",           "cat": "float",  "unit": "ratio","freshness": "heartbeat", "def": "2 x floors / circulating - the un-buyable base, a lower bound on LF, not on price", "constraint": "minLf" },
    { "id": "price.odinUsd",         "cat": "price",  "unit": "USD",  "freshness": "heartbeat", "def": "MEDIAN across pools where ODIN is the base token - a network property, never one pair", "constraint": "price" },
    { "id": "price.watch",           "cat": "price",  "unit": "per-token USD", "freshness": "heartbeat", "def": "paired-token prices, each from its own deepest base-side market; pool-implied fallback labelled implied" },
    { "id": "flow.vol24hUsd",        "cat": "flow",   "unit": "USD",  "freshness": "heartbeat", "def": "24h volume summed over locked pools with a live feed" },
    { "id": "flow.fees24hUsd",       "cat": "flow",   "unit": "USD",  "freshness": "heartbeat", "def": "vol24 x 0.003 - the FULL V2 swap fee enters reserves; k measures exactly this. OVERSTATES on MEV-heavy days; trailing k-growth is the honest basis", "constraint": "fees" },
    { "id": "flow.feeApyKGrowthPct", "cat": "flow",   "unit": "pct",  "freshness": "snapshot-only", "def": "reserve compounding measured from trailing k-growth - the preferred APY basis", "constraint": "apy" },
    { "id": "flow.tvrRoutedUsd",     "cat": "flow",   "unit": "USD",  "freshness": "snapshot-only", "def": "Total Value Routed: cumulative volume the locked pools processed, read from k alone" },
    { "id": "flow.tvrKeptUsd",       "cat": "flow",   "unit": "USD",  "freshness": "snapshot-only", "def": "the fee residue of TVR that compounded into the reserves; kept/routed reconciles at the swap fee rate" },
    { "id": "depth.swapOut",         "cat": "depth",  "unit": "function", "freshness": "heartbeat", "def": "exact V2 output at 0.30 pct trader fee - closed form from reserves; see /odinagents #derivations", "constraint": "depth" },
    { "id": "depth.book",            "cat": "depth",  "unit": "ladder","freshness": "heartbeat", "def": "the 16 pools stacked into one ladder: for each price level, ODIN absorbable = sum over pools of x(1/sqrt(p)-...) closed form; recipe in #recipes", "constraint": "depth" },
    { "id": "engine.podIndex",       "cat": "engine", "unit": "ODIN/pVAL", "freshness": "heartbeat", "def": "ODIN in pod / pVAL supply; ratchets up - a lower live read than a prior one is a bad read" },
    { "id": "engine.lockedShare",    "cat": "engine", "unit": "fraction",  "freshness": "heartbeat", "def": "burned spVAL / spVAL supply - the share of the sink pool that can never be unstaked" },
    { "id": "engine.pvalAtDeadPct",  "cat": "engine", "unit": "pct",  "freshness": "heartbeat", "def": "share of pVAL supply at the dead address" },
    { "id": "engine.stakerAprPct",   "cat": "engine", "unit": "pct",  "freshness": "snapshot-only", "def": "pod index growth annualized - ALWAYS name the window; whole-life figures embed the launch era", "constraint": "apy" },
    { "id": "engine.indexRatchet",   "cat": "engine", "unit": "days", "freshness": "snapshot-only", "def": "measured consecutive days without an index decline" },
    { "id": "div.independentBets",   "cat": "diversification", "unit": "count", "freshness": "snapshot-only", "def": "effective number of independent bets across the paired assets (eigenvalue method, external-venue prices - never pool-implied)" },
    { "id": "div.lpLegBets",         "cat": "diversification", "unit": "count", "freshness": "snapshot-only", "def": "same measure across LP legs - lower because every leg is half ODIN" }
  ]
}
[ 2 · SNAPSHOT — DATED, BLOCK-STAMPED, NEVER LIVE-DRESSED ]
{
  "meta": { "provenance": "snapshot", "date": "2026-07-22", "block": 25584535,
    "rule": "The honest fallback. Heartbeat metrics: recompute via #recipes before relying. Snapshot-only metrics carry their own measurement date.",
    "registryNote": "addresses and lock semantics live at /odinagents #registry - refuse any address not found there" },
  "supply": { "max": 500000000, "dead": 312592185, "pvalhallaBurn": 34001794,
    "floors": 2366886, "burned": 348960865, "burnedPct": 69.79, "circulating": 151039135,
    "floorsByPool": { "SOJ": 2236811, "TSUKA": 64592, "OHMI": 53286, "PEAS": 5181, "WAIT": 4823, "DBI": 1798, "APU": 389, "APE": 4, "SHIB": 1, "LINK": 1 } },
  "pools": { "lockedLiquidityUsd": 146300, "odinLocked": 59487093,
    "sumReservesNonEngine": 53462539, "engineOdinLocked": 6024554,
    "dormantAsOfSnapshot": ["SHIB","OHMI","SOJ","DBI"],
    "reserves": [
      { "pair": "WETH",  "oR": 8012830.74,  "pR": 5.275363184 },
      { "pair": "TSUKA", "oR": 6833013.15,  "pR": 9452882.009 },
      { "pair": "WBTC",  "oR": 6973761.974, "pR": 0.13279741 },
      { "pair": "PEAS",  "oR": 5798050.226, "pR": 8879.845445 },
      { "pair": "PAXG",  "oR": 5221989.06,  "pR": 1.629078527 },
      { "pair": "OHM",   "oR": 5164972.036, "pR": 355.3902601 },
      { "pair": "DAI",   "oR": 3970791.659, "pR": 5036.432422 },
      { "pair": "LINK",  "oR": 2336313.985, "pR": 340.7258404 },
      { "pair": "APU",   "oR": 1480063.738, "pR": 110427787.7 },
      { "pair": "APE",   "oR": 682611.136,  "pR": 5734.6947 },
      { "pair": "WAIT",  "oR": 515441.1722, "pR": 935725.2234 },
      { "pair": "SHIB",  "oR": 2028819.957, "pR": 599613828.8 },
      { "pair": "OHMI",  "oR": 1487415.383, "pR": 3582460.122 },
      { "pair": "SOJ",   "oR": 2572768.074, "pR": 0.8694181863 },
      { "pair": "DBI",   "oR": 383696.9947, "pR": 9371152.644 },
      { "pair": "pVALHALLA/pOHM", "engine": true, "oR": 6206246.078, "pR": 397.629076 } ] },
  "float": { "floatBasis": 153406021, "freeFloat": 93918928, "lf": 1.2668, "minLf": 0.0313 },
  "price": { "odinUsd": 0.00126353 },
  "flow": { "vol24hUsd": 6305, "fees24hUsdMeasured": 4.95,
    "flowNote": "measured fee income (metrics DB) does not reconcile with vol24 x any flat rate - fee income is k-growth-measured while volume is feed-reported. One more reason the k-growth basis wins.",
    "feeApyKGrowthPct": { "value": 4, "approx": true, "window": "trailing, measured 2026-07-27", "note": "the same day, vol24-annualizing read 25 pct - the MEV-day trap" },
    "tvrRoutedUsd": { "value": 19074957, "asOf": "2026-07-28", "method": "read from k alone - see #recipes" },
    "tvrKeptUsd":   { "value": 57224.87, "asOf": "2026-07-28" } },
  "engine": { "podIndex": 1.0200538508886943, "lockedShare": 0.9516402154933289,
    "pvalAtDeadPct": { "value": 52.08, "asOf": "2026-07-29" },
    "stakerAprPct": { "value": 0.283, "approx": true, "window": "trailing-year basis, measured 2026-07-29", "note": "the whole-life figure (about 1.04 pct) embeds the launch window - always name the window" },
    "indexRatchet": { "days": 702, "declines": 0, "asOf": "2026-07-29" } },
  "diversification": { "independentBets": { "value": 2.75, "assets": 15, "asOf": "2026-07-28" },
    "lpLegBets": { "value": 1.13, "asOf": "2026-07-28", "note": "every LP leg is half ODIN, so legs co-move" },
    "basis": "external-venue daily prices, never pool-implied; eigenvalue effective-bets method" }
}
[ 3 · RECIPES — RECOMPUTE ANY HEARTBEAT METRIC, NOW ]
Open, keyless endpoints. Selectors + canonical addresses: /odinagents #registry.
Formulas: /odinagents #derivations (this page embeds the same ones in
#livecode and runs them on itself in a browser context).

R1 · RESERVES + PRICE + VOLUME (one batch)
  GET https://api.dexscreener.com/token-pairs/v1/ethereum/{ODIN}
  For each returned pair whose pairAddress is in the locked registry:
  liquidity.base/quote are the reserves (base = the ODIN side when
  baseToken.symbol is ODIN), volume.h24 is the pool's 24h volume, priceUsd is
  that pool's ODIN print. price.odinUsd = MEDIAN over ODIN-base prints only.
  A registry pool ABSENT from the response is dormant (derived, not stored):
  read its reserves on-chain via getReserves() and value it at the network
  price, labelled implied. Trust dormancy re-derivation only when the feed
  answered for a majority of the registry - a thin response means "could not
  see", never "went quiet".

R2 · THE BURN, LIVE
  dead        = balanceOf(DEAD) at ODIN  (guard: within 10 pct of snapshot -
                this quantity moves slowly; a wild jump is a decode error)
  floors      = sum over capped pairs of (oR x pR) / totalSupply(pairedToken)
                (re-read caps live - PEAS burns, so its floor RISES; guard:
                a cap jumping UP or halving is a bad proxy/decimals read)
  pvalhallaBurn stays snapshot (mechanism-derived from the pod ledger)
  burned      = dead + pvalhallaBurn + floors ; circulating = max - burned

R3 · FLOAT + LF
  odinLocked  = sum(non-engine oR) + engine.pvalReserve x podIndex x lockedShare
  floatBasis  = max - dead - pvalhallaBurn
  freeFloat   = floatBasis - odinLocked      (NEVER circulating - odinLocked)
  lf = 2 x odinLocked / freeFloat ; minLf = 2 x floors / circulating

R4 · THE SINK
  podIndex    = balanceOf(ODIN at PVAL) / totalSupply(PVAL)   - must be at
                least 1 and never below a previously accepted live read
  lockedShare = balanceOf(SPVAL at DEAD) / totalSupply(SPVAL)
  pvalAtDeadPct = balanceOf(PVAL at DEAD) / totalSupply(PVAL) x 100

R5 · DEPTH / BOOK (pure arithmetic, zero fetches beyond R1)
  swapOut(a, rIn, rOut) = a x 997 x rOut / (rIn x 1000 + a x 997)
  Ladder: to move a pool's price to fraction f of spot (f below 1, selling),
  ODIN absorbed by that pool = oR x (1/sqrt(f) - 1) before fees; stack all 16
  (sink pool excluded - its book is pod-denominated). The MODELLED ladder;
  the MEASURED route is a live quote (CoW Swap /api/v1/quote, keyless).

R6 · SNAPSHOT-ONLY METHODS (reproduce the measurement, not just the number)
  feeApyKGrowthPct: k ratchets only from fees, so growth of sqrt(k) between
    two blocks IS the compounded fee income - annualize that, never vol24.
  TVR: cumulative routed volume recovered from the k series alone:
    each day's fee growth implies the volume that paid it at the fee rate;
    kept/routed must reconcile at the swap fee rate (assert it).
  stakerAprPct: pod index series, growth over a NAMED trailing window.
  independentBets: daily external-venue returns matrix, correlation
    eigenvalues, effective bets = (sum lambda)^2 / sum(lambda^2).

R7 · ONE CALL, THE WHOLE CANONICAL STATE (Multicall3)
  Multicall3 0xcA11bde05977b3631167028862bE2a173976CA11 (same address on
  every chain), method aggregate3((address,bool,bytes)[]), selector
  0x82ad56cb, allowFailure true on each call. The canonical read:
    getReserves()   0x0902f1ac            at each of the 16 registry pools
    balanceOf(DEAD) 0x70a08231+pad32(DEAD) at ODIN, at PVAL, at SPVAL
    balanceOf(PVAL) 0x70a08231+pad32(PVAL) at ODIN     (the pod position)
    totalSupply()   0x18160ddd            at PVAL, at SPVAL,
                                          at the 10 capped paired tokens
  = 32 calls, ONE eth_call, one block: a same-block atomic snapshot, which
  the per-call road cannot guarantee. Decode getReserves as
  (uint112 r0, uint112 r1, uint32 ts); ODIN is token1 in all 15 ODIN pools.
  Feed the decoded values to R2-R4 exactly as written.

R8 · GET-ONLY SANDBOX - RESERVES WITHOUT eth_call
  Some agent sandboxes can only GET. Explorer GET APIs expose balanceOf,
  and for a synced V2 pair balanceOf(token, pairAddress) EQUALS that
  token's reserve (sync() writes balances into reserves; a donation before
  sync overstates briefly - cross-check two sources when it matters).
  DexScreener (R1) is also plain GET. R2-R5 are then pure arithmetic.

R9 · THE k SERIES (the recorded prior state that k-growth metrics need)
  Daily append-only history since genesis (2023-02-06), block-stamped, one
  row per day: per-pool k, floors, dead balance, podIndex, lockedShare.
  FILE k_history_v1.json - published as a CORS-fetchable asset; its URL is
  on the trust anchor page (/odinagents, CANONICAL URLS); verify by
  sha256 10d4796c5d79008b3f91b2c9ae1d11f7e70ad111d2975025770169fe126f4eda
  Columns, caps (FULL precision), and the cap-history caveat are in-file.
  Trailing k-growth over a window = sqrt(k_end / k_start) - 1 per pool:
  that IS the compounded fee return (R6). History never changes - reserves
  at a past block are immutable facts; regeneration only appends rows.
[ 4 · LIVE — WRITTEN BY THIS PAGE AT LOAD, IN A BROWSER CONTEXT ]
{ "provenance": "static copy - no live read has run. Fetch-mode consumers: use
  #snapshot + #recipes. Browser-mode consumers: this block is rewritten with a
  fresh read at load; window.ODIN_ANALYTICS.refresh() re-reads on demand." }
[ 5 · LIVE CODE — THE FETCH LAYER, DISPLAYED = EXECUTED ]
/* The live layer. The runner compiles THIS displayed source and executes it -
   there is no hidden second copy. Guards mirror the odinOS data hub: a bad
   read keeps the labelled snapshot, never publishes a wrong number.
   Addresses duplicated here from /odinagents #registry for self-containment;
   that page remains canonical. */
var LIVE = {};
LIVE.run = function(SNAP){
  var ODIN = "0xDfC5964141c018485b4d017634660f85aa667714";
  var PVAL = "0xA77013378dAc318802dddF40bD7C7EF5dB594c95";
  var SPVAL = "0x80517Ad00bb79079DAdf009a9F6c6B8534F2fb80";
  var DEAD = "0x000000000000000000000000000000000000dEaD";
  var POOLS = [
    { pair: "WETH",  addr: "0x01dbAa18e86F65DF04cE9F897d2cAb22Ef0c26CB", tok: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" },
    { pair: "TSUKA", addr: "0xc0376b0Cbc8E92BCC21e6B9a2f1a2351E714C6E6", tok: "0xc5fB36dd2fb59d3B98dEfF88425a3F425Ee469eD", snapCap: 1000000000 },
    { pair: "WBTC",  addr: "0xAd673E520Aada71CF73CD8e257A5d50c78EB01a0", tok: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599" },
    { pair: "PEAS",  addr: "0xBaF9705037c14ad072A0DAF87Cd113de1A2A2F51", tok: "0x02f92800F57BCD74066F5709F1Daa1A4302Df875", snapCap: 9937294.670594584 },
    { pair: "PAXG",  addr: "0x2808F174244D17F1878ec03fd111222A4E4e4892", tok: "0x45804880De22913dAFE09f4980848ECE6EcbAf78" },
    { pair: "OHM",   addr: "0x08B30F89b3152E9815c79D8cf59eF8425693B08d", tok: "0x64aa3364F17a4D01c6f1751Fd97C2BD3D7e7f1D5" },
    { pair: "DAI",   addr: "0x6c027635A22FaaF29b9F565D543f91236c1864FE", tok: "0x6B175474E89094C44Da98b954EedeAC495271d0F" },
    { pair: "LINK",  addr: "0x62cB46A15589aC8712610AF26235Bfe99B9f553f", tok: "0x514910771AF9Ca656af840dff83E8264EcF986CA", snapCap: 1000000000 },
    { pair: "APU",   addr: "0x37C7Fde50966F36c3c5ff3379f817bf6A8C9745C", tok: "0x594DaaD7D77592a2b97b725A7AD59D7E188b5bFa", snapCap: 420690000000 },
    { pair: "APE",   addr: "0xFA7ea3c400115f67690E8b21Bfec5Da8C539a18D", tok: "0x4d224452801ACEd8B2F0aebE155379bb5D594381", snapCap: 1000000000 },
    { pair: "WAIT",  addr: "0x348B9E201641a10A824Fc607383Ba2B455C23D79", tok: "0x2559813BBb508C4C79e9CCCE4703Bcb1f149EDd7", snapCap: 100000000 },
    { pair: "SHIB",  addr: "0x3FeB0845e90F49c010C7704e44af829ACB9e61d1", tok: "0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE", snapCap: 999982329478394 },
    { pair: "OHMI",  addr: "0xdDf33339f86CcD48fFEd72b0F22C6e9669b1e2AB", tok: "0x4159862bcf6b4393a80550b1ed03dffa6f90533c", snapCap: 100000000 },
    { pair: "SOJ",   addr: "0x440944d4f7b7A32349724612b757a1d5f1E624B9", tok: "0x5830d25d257e46084361f8dc5e758736fd45a27a", snapCap: 1 },
    { pair: "DBI",   addr: "0x97EEd004224B6c68B6752D89207CaB28c8fbD09e", tok: "0x2de509bf0014ddf697b220be628213034d320ece", snapCap: 2000000000 },
    { pair: "ENGINE", engine: true, addr: "0x4Bcd9c0397401232eA65F6790aA8a3837FdBC8B1" }
  ];
  var RPCS = ["https://eth.drpc.org", "https://ethereum-rpc.publicnode.com", "https://cloudflare-eth.com"];
  var errors = [];
  function rpc(to, data){
    function attempt(i){
      if(i >= RPCS.length) return Promise.reject(new Error("all rpcs failed"));
      return fetch(RPCS[i], { method: "POST", headers: { "content-type": "application/json" },
        body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_call", params: [{ to: to, data: data }, "latest"] }) })
        .then(function(r){ if(!r.ok) throw 0; return r.json(); })
        .then(function(j){ if(j.error) throw 0; if(j.result == null) throw 0; return j.result; })
        .catch(function(){ return attempt(i + 1); });
    }
    return attempt(0);
  }
  function pad(a){ return "000000000000000000000000" + a.slice(2).toLowerCase(); }
  function bal(token, holder){ return rpc(token, "0x70a08231" + pad(holder)).then(function(h){ return parseInt(h, 16) / 1e18; }); }
  function sup18(token){ return rpc(token, "0x18160ddd").then(function(h){ return parseInt(h, 16) / 1e18; }); }
  function capOf(p){
    return Promise.all([rpc(p.tok, "0x18160ddd"), rpc(p.tok, "0x313ce567")]).then(function(r){
      var d = parseInt(r[1], 16);
      var v = Number(BigInt(r[0])) / Math.pow(10, d);
      if(!isFinite(v)) throw 0;
      if(!(v > 0)) throw 0;
      if(v > p.snapCap * 1.0001) throw 0;         /* caps never jump up */
      if(p.snapCap > 2 * v) throw 0;              /* nor halve - bad decimals read */
      return v;
    }).catch(function(){ errors.push("cap:" + p.pair + " snapshot kept"); return p.snapCap; });
  }
  function feed(){
    return fetch("https://api.dexscreener.com/token-pairs/v1/ethereum/" + ODIN)
      .then(function(r){ if(!r.ok) throw 0; return r.json(); })
      .then(function(j){ return Array.isArray(j) ? j : (j.pairs ? j.pairs : []); });
  }
  var snapReserves = {};
  SNAP.pools.reserves.forEach(function(p){ snapReserves[p.pair] = p; });
  var out = { at: new Date().toISOString(), provenance: {}, errors: errors };
  return Promise.all([
    feed().catch(function(){ errors.push("feed unreachable"); return null; }),
    bal(ODIN, DEAD).catch(function(){ return null; }),
    Promise.all(POOLS.filter(function(p){ return p.snapCap > 0; }).map(function(p){
      return capOf(p).then(function(v){ return { pair: p.pair, cap: v }; }); })),
    Promise.all([bal(ODIN, PVAL), sup18(PVAL), bal(SPVAL, DEAD), sup18(SPVAL), bal(PVAL, DEAD)]).catch(function(){ return null; }),
    rpc(POOLS[15].addr, "0x0902f1ac").catch(function(){ return null; })
  ]).then(function(res){
    var pairsRaw = res[0], deadLive = res[1], caps = res[2], pod = res[3], engRes = res[4];
    /* pools: live reserves where the feed answered; dormancy re-derived only
       when a majority answered ("could not see" must never read as "quiet") */
    var map = {};
    if(pairsRaw){ pairsRaw.forEach(function(d){ if(d){ if(d.pairAddress) map[d.pairAddress.toLowerCase()] = d; } }); }
    var nonEngine = POOLS.filter(function(p){ return !p.engine; });
    var seen = nonEngine.filter(function(p){ return map[p.addr.toLowerCase()]; }).length;
    var trustDorm = seen * 2 > nonEngine.length;
    var prints = [], vol24 = 0, volKnown = false, dormant = [], reserves = [], liqUsd = 0;
    nonEngine.forEach(function(p){
      var d = map[p.addr.toLowerCase()], s = snapReserves[p.pair];
      var row = { pair: p.pair, oR: s.oR, pR: s.pR, prov: "snapshot" };
      if(d){
        var bs = String(d.baseToken ? d.baseToken.symbol : "").toUpperCase();
        var odinBase = bs === "ODIN";
        if(d.liquidity){
          if(d.liquidity.base > 0){ if(d.liquidity.quote > 0){
            row.oR = odinBase ? d.liquidity.base : d.liquidity.quote;
            row.pR = odinBase ? d.liquidity.quote : d.liquidity.base;
            row.prov = "live"; } }
          if(d.liquidity.usd > 0){ row.liqUsd = d.liquidity.usd; liqUsd += d.liquidity.usd; }
        }
        if(d.volume){ if(isFinite(+d.volume.h24)){ vol24 += +d.volume.h24; volKnown = true; } }
        if(odinBase){ if(+d.priceUsd > 0) prints.push(+d.priceUsd); }
      } else if(trustDorm){ dormant.push(p.pair); }
      row.k = row.oR * row.pR;
      reserves.push(row);
    });
    prints.sort(function(a, b){ return a - b; });
    var price = prints.length ? prints[Math.floor(prints.length / 2)] : SNAP.price.odinUsd;
    out.price = { odinUsd: price, prints: prints.length };
    out.provenance.price = prints.length ? "live median of " + prints.length + " base-side prints" : "snapshot";
    /* dormant pools: value from chain reserves at the network price, implied */
    dormant.forEach(function(pair){
      var row = reserves.filter(function(r){ return r.pair === pair; })[0];
      row.liqUsd = 2 * row.oR * price; row.prov = row.prov + " · implied-value";
      liqUsd += row.liqUsd;
    });
    /* the burn */
    var dead = SNAP.supply.dead, deadProv = "snapshot";
    if(deadLive){ if(deadLive > 0){
      if(Math.abs(deadLive - SNAP.supply.dead) / SNAP.supply.dead > 0.10){ errors.push("dead read outside guard - snapshot kept"); }
      else { dead = deadLive; deadProv = "live"; } } }
    var capMap = {}; caps.forEach(function(c){ capMap[c.pair] = c.cap; });
    var capsLive = caps.length - errors.filter(function(e){ return e.indexOf("cap:") === 0; }).length;
    var floors = 0, floorsByPool = {};
    reserves.forEach(function(r){
      var c = capMap[r.pair];
      if(c > 0){ var f = r.k / c; floors += f; floorsByPool[r.pair] = Math.round(f); }
    });
    var burned = dead + SNAP.supply.pvalhallaBurn + floors;
    var circulating = SNAP.supply.max - burned;
    out.supply = { max: SNAP.supply.max, dead: dead, pvalhallaBurn: SNAP.supply.pvalhallaBurn,
      floors: Math.round(floors), floorsByPool: floorsByPool, burned: Math.round(burned),
      burnedPct: Math.round(10000 * burned / SNAP.supply.max) / 100, circulating: Math.round(circulating) };
    out.provenance.supply = deadProv + " dead · snapshot pvalhallaBurn · floors from " + capsLive + " of " + caps.length + " live caps";
    /* the engine */
    var podIndex = SNAP.engine.podIndex, lockedShare = SNAP.engine.lockedShare,
        pvalAtDeadPct = SNAP.engine.pvalAtDeadPct.value, engProv = "snapshot";
    if(pod){
      var i0 = pod[0] / pod[1], sh = pod[2] / pod[3];
      var ok = true;
      if(!(i0 > 0.5)) ok = false;
      if(i0 > 5) ok = false;
      if(!(sh > 0)) ok = false;
      if(sh > 1) ok = false;
      if(SNAP.engine.podIndex > i0 + 1e-9) ok = false;   /* the ratchet: live must not sit below the past */
      if(ok){ podIndex = i0; lockedShare = sh; pvalAtDeadPct = Math.round(10000 * pod[4] / pod[1]) / 100; engProv = "live"; }
      else { errors.push("pod read failed guards - snapshot kept"); }
    }
    out.engine = { podIndex: podIndex, lockedShare: lockedShare, pvalAtDeadPct: pvalAtDeadPct };
    out.provenance.engine = engProv;
    /* sink pool reserves: token0 is pOHM (lower address), token1 is pVALHALLA */
    var engPvR = snapReserves["pVALHALLA/pOHM"].oR, engProv2 = "snapshot";
    if(engRes){
      var r0 = parseInt(engRes.slice(2, 66), 16) / 1e18, r1 = parseInt(engRes.slice(66, 130), 16) / 1e18;
      if(r1 > 0){ engPvR = r1; engProv2 = "live"; }
    }
    reserves.push({ pair: "pVALHALLA/pOHM", engine: true, pvR: engPvR, prov: engProv2 });
    /* float + LF */
    var odinLocked = 0;
    reserves.forEach(function(r){
      if(r.engine){ odinLocked += r.pvR * podIndex * lockedShare; } else { odinLocked += r.oR; }
    });
    var floatBasis = SNAP.supply.max - dead - SNAP.supply.pvalhallaBurn;
    var freeFloat = floatBasis - odinLocked;
    out.pools = { odinLocked: Math.round(odinLocked), lockedLiquidityUsd: Math.round(liqUsd),
      dormant: trustDorm ? dormant : SNAP.pools.dormantAsOfSnapshot, reserves: reserves };
    out.provenance.pools = pairsRaw ? ("feed live · " + seen + " of " + nonEngine.length + " listed") : "snapshot";
    out.float = { floatBasis: Math.round(floatBasis), freeFloat: Math.round(freeFloat),
      lf: Math.round(10000 * 2 * odinLocked / freeFloat) / 10000,
      minLf: Math.round(10000 * 2 * floors / circulating) / 10000 };
    out.provenance.float = "derived from the reads above - identities hold by construction";
    out.flow = volKnown
      ? { vol24hUsd: Math.round(vol24), fees24hUsd: Math.round(100 * vol24 * 0.003) / 100,
          basis: "vol24 x 0.003 - the full V2 swap fee enters reserves, which is what k measures and what the TVR test above reconciles at. Overstates on MEV-heavy days; trailing k-growth is the honest basis" }
      : { vol24hUsd: null, note: "no live volume - nothing fabricated" };
    out.provenance.flow = volKnown ? "live" : "unavailable";
    return out;
  });
};
[ 6 · SELF-TEST — THE CATALOG PROVES ITSELF ]
/* Runs at load against the displayed #schema and #snapshot. Identities and
   reconciliations, not just values - a catalog whose own numbers do not
   reconcile is not a data plane, it is a brochure. */
function runSelfTest(SCHEMA, SNAP){
  var R = [];
  function t(name, pass, detail){ R.push({ name: name, pass: !!pass, detail: detail }); }
  /* catalog shape */
  var ids = {}; var dup = false;
  SCHEMA.metrics.forEach(function(m){ if(ids[m.id]) dup = true; ids[m.id] = m; });
  t("schema: metric ids unique", !dup, String(SCHEMA.metrics.length) + " metrics");
  var catSet = {};
  SCHEMA.metrics.forEach(function(m){ catSet[m.cat] = 1; });
  t("schema: every declared category is populated",
    SCHEMA.categories.every(function(c){ return catSet[c] === 1; }), SCHEMA.categories.join(","));
  var fresh = SCHEMA.metrics.every(function(m){
    if(m.freshness === "heartbeat") return true;
    if(m.freshness === "snapshot-only") return true;
    return m.freshness === "constant";
  });
  t("schema: freshness class is always declared", fresh, "");
  /* snapshot-only metrics must carry their own measurement date */
  var dated = [SNAP.flow.feeApyKGrowthPct.window, SNAP.flow.tvrRoutedUsd.asOf,
    SNAP.engine.stakerAprPct.window, SNAP.engine.indexRatchet.asOf,
    SNAP.diversification.independentBets.asOf].every(function(x){ return typeof x === "string"; });
  t("snapshot: every snapshot-only metric names its date or window", dated, "");
  /* burn accounting reconciles from its own parts */
  var floorsSum = 0;
  Object.keys(SNAP.supply.floorsByPool).forEach(function(k){ floorsSum += SNAP.supply.floorsByPool[k]; });
  t("supply: floorsByPool sums to floors", 3 > Math.abs(floorsSum - SNAP.supply.floors), String(floorsSum));
  t("supply: SOJ dominates the floors (94.5 pct)",
    0.2 > Math.abs(100 * SNAP.supply.floorsByPool.SOJ / SNAP.supply.floors - 94.5), "");
  var burned = SNAP.supply.dead + SNAP.supply.pvalhallaBurn + SNAP.supply.floors;
  t("supply: dead + pvalhallaBurn + floors = burned", 1 > Math.abs(burned - SNAP.supply.burned), "");
  t("supply: circulating = max - burned",
    1 > Math.abs(SNAP.supply.max - burned - SNAP.supply.circulating), "");
  /* reserves reproduce the aggregates */
  var sumOR = 0;
  SNAP.pools.reserves.forEach(function(p){ if(!p.engine) sumOR += p.oR; });
  t("pools: reserve sum reproduces sumReservesNonEngine", 2 > Math.abs(sumOR - SNAP.pools.sumReservesNonEngine), sumOR.toFixed(0));
  var eng = SNAP.pools.reserves.filter(function(p){ return p.engine; })[0];
  var engLocked = eng.oR * SNAP.engine.podIndex * SNAP.engine.lockedShare;
  t("pools: engine locked = pvR x podIndex x lockedShare", 2 > Math.abs(engLocked - SNAP.pools.engineOdinLocked), engLocked.toFixed(0));
  t("pools: odinLocked = reserves + engine share",
    3 > Math.abs(sumOR + engLocked - SNAP.pools.odinLocked), "");
  /* the float identities */
  t("IDENTITY: floatBasis = max - dead - pvalhallaBurn",
    1 > Math.abs(SNAP.supply.max - SNAP.supply.dead - SNAP.supply.pvalhallaBurn - SNAP.float.floatBasis), "");
  t("IDENTITY: floatBasis = odinLocked + freeFloat",
    3 > Math.abs(SNAP.float.floatBasis - SNAP.pools.odinLocked - SNAP.float.freeFloat), "");
  t("float: lf recomputes", 0.0005 > Math.abs(2 * SNAP.pools.odinLocked / SNAP.float.freeFloat - SNAP.float.lf), "");
  t("float: minLf recomputes", 0.0005 > Math.abs(2 * SNAP.supply.floors / SNAP.supply.circulating - SNAP.float.minLf), "");
  /* TVR reconciles at the swap fee rate - kept IS the fee residue of routed */
  var ratio = SNAP.flow.tvrKeptUsd.value / SNAP.flow.tvrRoutedUsd.value;
  t("flow: TVR kept/routed reconciles at the 0.30 pct swap fee",
    (function(){ if(ratio > 0.0029){ return 0.0031 > ratio; } return false; })(), ratio.toFixed(5));
  /* basis discipline is stated, not implied */
  t("flow: k-growth basis carries its window",
    SNAP.flow.feeApyKGrowthPct.window.indexOf("trailing") === 0, SNAP.flow.feeApyKGrowthPct.window);
  t("engine: staker APR names its window",
    SNAP.engine.stakerAprPct.window.indexOf("trailing") === 0, SNAP.engine.stakerAprPct.window);
  t("engine: index ratchet is unbroken", SNAP.engine.indexRatchet.declines === 0,
    SNAP.engine.indexRatchet.days + " days");
  t("engine: pod index above 1", SNAP.engine.podIndex > 1, "");
  /* diversification sanity: bets bounded by asset count, legs below assets */
  var b = SNAP.diversification.independentBets;
  t("div: independent bets within (1, assets)",
    (function(){ if(b.value > 1){ return b.assets > b.value; } return false; })(), String(b.value));
  t("div: LP legs measure below the asset measure",
    b.value > SNAP.diversification.lpLegBets.value, String(SNAP.diversification.lpLegBets.value));
  return R;
}
self-test pending - enable JavaScript, or run the same checks yourself: that is the point.
[ 7 · BOUNDARIES ]
READ-ONLY, PREDICTION-FREE, PERSON-FREE, ADVICE-FREE, CHAIN-FIRST - the full
statements live at /odinagents #boundaries and bind this page identically.

Specific to this plane:
  - NOTHING IS FABRICATED. A metric whose read fails keeps its labelled
    snapshot; a metric with no honest source reads null with a note. An
    empty field is a measurement too.
  - THE HEARTBEAT IS YOURS. This page fetches once at load. Poll by calling
    window.ODIN_ANALYTICS.refresh(), or run #recipes on your own schedule -
    the endpoints are open and keyless precisely so you do not need us.
  - SNAPSHOT-ONLY METRICS are measurements from the network's history
    archive, dated. Reproduce them via the methods in R6 before extending
    them; do not extrapolate them forward.
  - INTEGRITY: confirm the ODIN address in #livecode matches /odinagents
    #registry; run the self-test; on any failure trust the chain, not this page.